Как привязать RadioButton к свойству через словарь - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть список объектов разных типов. Некоторые из них имеют тип RadioProperty.
Каждый объект имеет некоторые свойства. Интерес представляют следующие:

string PropName; // property name
string Value; // current property value
Dictionary<string, string> Values; // possible values - name, value

Value должно в любое время иметь одно из значений, доступных в словаре. Я хочу как-то связать это с группой переключателей, чтобы я мог выбрать значение свойства из доступных значений в словаре.
На данный момент это то, что у меня есть:
Я упростил код для презентаций. Надеюсь, я не пропустил ничего важного.

XAML

<StackPanel>
  <StackPanel.Resources>
    <local:RadioPropertyConverter x:Key="radioPropertyConverter" />
  </StackPanel.Resources>
  <ItemsControl x:Name="PropertyList" ItemsSource="{Binding PropList}">
    <ItemsControl.Resources>
      <DataTemplate DataType="{x:Type proptool:RadioProperty}">
        <StackPanel>
          <Grid>
            <StackPanel>
              <ItemsControl ItemsSource="{Binding Values}">
                <ItemsControl.ItemTemplate>
                  <DataTemplate>
                    <RadioButton Content="{Binding Path=Key}">
                      <!-- BEGIN: GroupName is equal to PropName -->
                      <RadioButton.GroupName>
                        <Binding Path="DataContext.PropName">
                          <Binding.RelativeSource>
                            <RelativeSource Mode="FindAncestor"
                                            AncestorType="{x:Type TypeName=StackPanel}" />
                          </Binding.RelativeSource>
                        </Binding>
                      </RadioButton.GroupName>
                      <!-- END -->
                      <RadioButton.IsChecked>
                        <!-- specifying only `Value` for Path will fail at
                        runtime with the following error:
                        System.Windows.Markup.XamlParseException: 'A TwoWay or
                        OneWayToSource binding cannot work on the read-only
                        property 'Value' of type
                        'System.Collections.Generic.KeyValuePair`2[System.String,System.String]'.' -->
                        <Binding Converter="{StaticResource radioPropertyConverter}"
                                 Path="/Value" ConverterParameter="Y" />
                      </RadioButton.IsChecked>
                    </RadioButton>
                  </DataTemplate>
                </ItemsControl.ItemTemplate>
              </ItemsControl>
            </StackPanel>
          </Grid>
        </StackPanel>
      </DataTemplate>
    </ItemsControl.Resources>
  </ItemsControl>
</StackPanel>

PropList имеет тип List<RadioProperty>.
Значение для ConverterParameter должно быть равно текущему значению в словаре. Кажется, невозможно указать привязку для параметра ConverterParameter:
System.Windows.Markup.XamlParseException: «Связывание» не может быть установлено в свойстве «ConverterParameter» типа «Связывание». «Привязка» может быть установлена ​​только в свойстве DependencyProperty объекта DependencyObject. '

C #

public class RadioPropertyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return value?.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return value?.Equals(true) == true ? parameter : Binding.DoNothing;
    }
}

Не думаю, что конвертер должен выглядеть так, но текущая проблема, с которой я столкнулся, заключается в том, что методы Convert / ConvertBack никогда не вызываются.

Чего я хочу добиться, так это иметь список свойств, каждое из которых содержит некоторые детали в разных элементах управления. Каждое свойство может иметь собственный список (Values), который должен быть представлен пользователю в виде списка переключателей. В зависимости от значения Value должен быть выбран определенный переключатель. Если выбран другой переключатель, значение должно измениться соответственно. Поэтому я думаю, что привязка должна быть выполнена с Value и переключателями, отображаемыми в зависимости от содержимого словаря (у меня уже есть эта работа).

Я прошу вас не указывать мне другие вопросы, так как я уверен, что прошел большинство из тех, которые связаны с моим вопросом. Если, конечно, если вы поняли мой вопрос и думаете, что я мог пропустить некоторые детали в некоторых из уже отвеченных вопросов.

Некоторые из, по-видимому, более актуальных вопросов SO для моего конкретного сценария, через которые я уже прошел:

  1. Привязка RadioButton к словарю
  2. Как привязать RadioButtons к перечислению?

1 Ответ

0 голосов
/ 08 ноября 2018

Эта ошибка, связанная с тем, что вы получаете привязку к значению «Value», существует по причине, вы не можете обмануть ее значением «/ Value» и ожидать, что она исчезнет. Также есть много SO вопросов по этому поводу, хотя это может быть немного сложно найти и понять их без значительных усилий.

Чтобы ответить на ваш вопрос, я не знаю точных причин того, почему, но переключатели никогда не работали «из коробки» с WPF, предположительно потому, что существует слишком много разных способов, которыми людям нужно их подключать. вверх. В вашем случае вам нужно сделать две вещи:

1) Получите привязку OneWay от RadioProperty к работающей кнопке управления. Вы уже заметили, что параметры конвертера не могут использовать привязки, вместо этого можно использовать мультиконвертер:

public class RadioPropertyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null)
            return false;
        if (values.Length != 2)
            return false;
        return Object.Equals(values[0], values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Забудьте о ConvertBack, в этом контексте это бессмысленно, и оно вам не понадобится. Вернувшись в свой XAML, вы теперь используете это в теге OneWay MultiBinding в RadioButton.IsChecked, передавая значение RadioProperty и текущее значение словаря:

<RadioButton.IsChecked>
    <MultiBinding Converter="{StaticResource radioPropertyConverter}" Mode="OneWay">
        <Binding Path="Value" />
        <Binding Path="DataContext.Value" RelativeSource="{RelativeSource AncestorType={x:Type StackPanel}}" />
    </MultiBinding>
</RadioButton.IsChecked>

2) Получите привязку, работающую в другом направлении, т. Е. Щелчок переключателей обновляет соответствующее значение RadioProperty. На самом деле есть несколько различных способов сделать это, но тот, который я предпочитаю, использует тот факт, что переключатели, как и все другие кнопки, генерируют команды при нажатии (что вы, очевидно, уже заметили, учитывая наличие пустой команды обработчик в теге <RadioButton>). Все, что вам нужно сделать, это добавить привязку к обработчику команд в вашем классе RadioProperty и для передачи CommandParameter в значение Key для нажатой кнопки:

<RadioButton Content="{Binding Path=Key}"
     Command="{Binding Path=DataContext.SetValueCommand, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}"
     CommandParameter="{Binding Key}">

А затем вы просто добавляете обработчик ICommand в ваш класс RadioProperty, который принимает ключ и использует его для установки обоих PropName и Value:

    private ICommand _SetValueCommand;
    public ICommand SetValueCommand => this._SetValueCommand ?? (this._SetValueCommand = new RelayCommand<string>(OnSetValue));

    private void OnSetValue(string key)
    {
        this.PropName = key;
        this.Value = this.Values[key];
    }

Если у вас есть другие элементы управления, привязанные к тем же экземплярам RadioProperty, то вам также может потребоваться уведомить об изменении свойств PropName и Value, но в противном случае это должно работать нормально.

...