【问题标题】:How to bind a RadioButton to a property via a Dictionary如何通过字典将 RadioButton 绑定到属性
【发布时间】:2019-04-11 01:57:11
【问题描述】:

我有一个不同类型的对象列表。其中一些是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&lt;RadioProperty&gt;
ConverterParameter 的值应等于字典中的当前值。似乎无法为 ConverterParameter 指定绑定:
System.Windows.Markup.XamlParseException:“无法设置“绑定” “Binding”类型的“ConverterParameter”属性。只能在 DependencyObject 的 DependencyProperty 上设置“绑定”。'

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 问题,因为我非常有信心我已经完成了与我的问题相关的大部分问题。当然,除非你理解了我的问题,并且你认为我可能遗漏了一些已经回答的问题中的一些细节。

对于我已经经历过的特定场景,一些可能更相关的 SO 问题:

  1. Binding RadioButton to Dictionary
  2. How to bind RadioButtons to an enum?

【问题讨论】:

  • 您将路径指定为 Path="/Value" 而不是 Path="Value" 的任何原因?
  • @RandRandom,我在 XAML cmets 中 RadioButton.IsChecked 属性元素之后提到了原因。我仍然不知道为什么我只是指定Value它不起作用。
  • 我后来在我的评论中看到了这一点 - 但你确实意识到你所做的唯一一件事就是破坏你的有效输入,如果你写 Path="WTF_IsWrong" 现在你的运行时错误关于 wpf 抱怨两个由于您不再绑定到只读的 Value 属性,因此方式 binging 也消失了。 - 所以,是的,你的错误消失了,只是因为你破坏了你的有效输入。
  • 如果我为 Binding 的 Path 属性指定 Value 但它与 MultiBinding 一起使用,我仍然不明白为什么它不起作用。我会试着用谷歌搜索一下,看看有没有发现……

标签: c# wpf data-binding radio-button


【解决方案1】:

您绑定到“Value”的错误是有原因的,您不能用“/Value”来捏造它并期望它消失。还有很多关于此的 SO 问题,尽管在不付出大量努力的情况下找到并理解它们可能有点棘手。

要回答您的问题,我不知道确切的原因,但单选按钮从来没有在 WPF 中开箱即用地“工作”过,大概是因为人们需要用太多不同的方式来连接它们向上。在您的情况下,您需要做两件事:

1) 从 RadioProperty 获取 OneWay 绑定到单选按钮控件工作。您已经注意到转换器参数不能使用绑定,解决此问题的方法是使用多转换器:

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,您现在在 RadioButton.IsChecked 的 OneWay MultiBinding 标记中使用它,传入 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 值。实际上有几种不同的方法可以做到这一点,但我更喜欢的一种方法是利用单选按钮,像所有其他按钮一样,在单击时生成命令(考虑到空命令的存在,你显然已经习惯了这一点) &lt;RadioButton&gt; 标记中的处理程序)。您需要做的就是在 RadioProperty 类中添加与命令处理程序的绑定,并为 CommandParameter 传递所按下按钮的 Key 值:

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

然后您只需向 RadioProperty 类添加一个 ICommand 处理程序,该类接受密钥并使用它来设置 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 属性更改通知,否则应该可以正常工作。

【讨论】:

  • 这个解决方案对我来说是开箱即用的。不过,我不需要更改 PropName 的值。在向Value 发出属性更改通知后,一切都按预期工作。您能否用 empty Command handler 指定您所指的内容?我确实在某些时候偶然发现了命令,但并没有真正花时间研究它们,因为当时我不需要它们。我上个月刚开始学习 C# 和 WPF,所以答案对其他人来说可能很明显。非常感谢。
  • 对不起@Julian,出于某种原因,我以为我在您的代码中看到了Command=""(已经很晚了,我很累)。命令对于 MVVM 是必不可少的,而不是像按钮按下等通过事件定向到代码隐藏,而是允许您将它们定向到您的视图模型,因此它们对于保持良好的关注点分离和干净的架构设计很重要.很高兴听到它现在对您有用。
猜你喜欢
  • 1970-01-01
  • 2016-09-26
  • 2017-05-10
  • 2010-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 2020-03-07
相关资源
最近更新 更多