【问题标题】:WPF + MVVM + RadioButton : Handle binding with single propertyWPF + MVVM + RadioButton:使用单个属性处理绑定
【发布时间】:2016-10-13 21:18:15
【问题描述】:

thisthis(和其他)关于 SO 的问题以及互联网上的许多其他材料中,我了解了如何将单选按钮与 VM 绑定。

但它们都为单选按钮的每个可能值创建单独的属性。一个问题 (this) 与我的要求类似,但接受的答案建议使用 ListBox 而不是单选按钮。

要表示人的性别(数据类型 CHAR,可能的值 'M'、'F'),需要在 VM 中创建三个属性:PersonGender、IsPersonMale、IsPersonFemale。 我只想在一个属性 PersonGender 上控制它。 我可以这样做吗?如果是,怎么做?

【问题讨论】:

  • 在每个 RadioButton 上放置一个命令(相同)并将它们的值作为参数传递
  • @nkoniishvt:看起来很有趣;会试试这个。但仍不能完全接受。单选按钮代表用户输入和显示,如文本框或组合框;不像命令按钮那样的动作。使用命令处理输入/显示看起来不正确。
  • 命令是为 MVVM 制作的,如果你想拥有一个兼容 MVVM 的应用程序,你应该从 UI 绑定到命令。看看这样的教程:codeproject.com/Articles/238657/How-to-use-Commands-in-WPF

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


【解决方案1】:

你需要一个转换器。

//define this in the Window's Resources section or something similiarly suitable
<local:GenderConverter x:Key="genderConverterKey" />


<RadioButton Content="M" IsChecked="{Binding Gender, Converter={StaticResource ResourceKey=genderConverterKey}, ConverterParameter=M}" />
<RadioButton Content="F" IsChecked="{Binding Gender, Converter={StaticResource ResourceKey=genderConverterKey}, ConverterParameter=F}" />

转换器

public class GenderConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((string)parameter == (string)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? parameter : null;        
    }
}

如果在这种情况下不应应用绑定,请将null(在ConvertBack)替换为Binding.DoNothing

return (bool)value ? parameter : Binding.DoNothing;

【讨论】:

  • 如果在这种情况下不应应用绑定,请将 null(在 ConvertBack 中)替换为 Binding.DoNothing返回(布尔)值?参数:Binding.DoNothing;
  • 转换器中没有任何东西将其与 Gender 数据类型联系起来。因此,您可以重命名它以使其成为通用转换器。
  • 就我的口味而言,这个解决方案比命令解决方案更纯粹的 MVVM。
【解决方案2】:

使用命令(这里使用DelegateCommands

虚拟机:

public enum Genders {
    Female,
    Male
}
public YourVMClass {
    public Genders SelectedGender {get; set;}

    private DelegateCommand _cmdSelectGender;

    public DelegateCommand CmdSelectGender {
        get { return _cmdSelectGender ?? (_cmdSelectGender = new DelegateCommand(SelectGender)); }
    }

    private void SelectGender(Object parameter) {
        SelectedGender = (Genders)parameter;
    }
}

XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="listOfGenders" MethodName="GetValues"
                        ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="loca:Genders"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<ItemsControl ItemsSource="{Binding Source={StaticResources listOfGenders}}">
    <ItemsControl.ItemTemplate>
        <RadioButton GroupName="Genders" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MainWindow}}, Path=DataContext.CmdSelectGender}" CommandParameter="{Binding}"/>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

(没有测试代码,但这是思路)

【讨论】:

    【解决方案3】:

    您的要求是可能的,但您需要一些额外的努力才能使其发挥作用。其主要原因是 RadioButton 的属性 IsCheckedBoolean 并且多个单选按钮是独立的控件,不能像一个一样。例如一个列表框。

    为了满足您的要求,您可以使用转换器。 将两个 Radiobuttons 的 IsChecked 绑定到 ViewModel 中的 PersonGender 属性,并使用通用转换器并为男性单选按钮传递参数“MALE”,为女性单选按钮传递参数“FEMALE” .

    在 Converter 中检查 parameterPersonGender 是否相同并为此返回 TRUE

    即。如果 checkbox 命令参数是 MALE 并且 PersonGender 也是 MALE,那么复选框被启用 否则,如果复选框命令参数为 FEMALE 且 PersonGender 为 MALE,则不会启用复选框,因为返回 false。

    【讨论】:

      【解决方案4】:

      您需要做的是使用IValueConverter,将 Bool 转换为 Char,反之亦然。 示例 True => 'M';假 => 'F'

      在您的视图中有两个单选按钮。确保将它们设置在相同的组名中。 然后您需要将您的 PersonGender 绑定到仅 IsMale 单选按钮。 因为然后 IsFemale 单选按钮被选中。由于组名相同,IsMale 单选按钮将自动取消选中。

      【讨论】:

        【解决方案5】:

        我将 solution 转换器稍微更改为 MarkupExtension 以使其更易于使用(此处为 int-converter):

        public class RadioValueExtension : MarkupExtension, IValueConverter
        {
            [ConstructorArgument("value")]
            public int Value { get; set; }
        
            public RadioValueExtension(int value)
            {
                Value = value;    
            }
        
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                return this;
            }
        
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return Value == (int)value;
            }
        
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return (bool)value ? Value : Binding.DoNothing;
            }
        }
        

        所以我可以这样使用它

        <RadioButton IsChecked="{Binding Gender, Converter={converters:RadioValue 0}}" Content="M" />
        <RadioButton IsChecked="{Binding Gender, Converter={converters:RadioValue 1}}" Content="F" />
        

        【讨论】:

          猜你喜欢
          • 2016-09-26
          • 2010-12-20
          • 2020-04-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-16
          • 2019-02-28
          • 1970-01-01
          • 2011-11-10
          相关资源
          最近更新 更多