【问题标题】:How to bind RadioButtons to an enum?如何将 RadioButtons 绑定到枚举?
【发布时间】:2010-09-28 16:39:03
【问题描述】:

我有一个这样的枚举:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

我的 DataContext 中有一个属性:

public MyLovelyEnum VeryLovelyEnum { get; set; }

我的 WPF 客户端中有三个 RadioButtons。

<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>

现在如何将 RadioButtons 绑定到属性以进行正确的双向绑定?

【问题讨论】:

  • 如果您希望在 XAML 中不指定单个 RadioButtons 的情况下执行此操作,我建议您将 ListBox 绑定到 thisthis 等枚举值,并覆盖项目模板使用像 this 这样的 RadioButtons。

标签: wpf data-binding enums radio-button


【解决方案1】:

您可以进一步简化接受的答案。您可以显式传入枚举值而不是字符串表示,而不是在 xaml 中将枚举作为字符串输入并在转换器中做更多的工作,而不是像 CrimsonX 评论的那样,在编译时而不是运行时抛出错误:

ConverterParameter={x:Static local:YourEnumType.Enum1}

<StackPanel>
    <StackPanel.Resources>          
        <local:ComparisonConverter x:Key="ComparisonConverter" />          
    </StackPanel.Resources>
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" />
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" />
</StackPanel>

然后简化转换器:

public class ComparisonConverter : 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;
    }
}

编辑(2010 年 12 月 16 日):

感谢匿名 suggesting 返回 Binding.DoNothing 而不是 DependencyProperty.UnsetValue。


注意 - 同一容器中的多组 RadioButtons(2011 年 2 月 17 日):

在 xaml 中,如果单选按钮共享相同的父容器,则选择一个将取消选择该容器内的所有其他按钮(即使它们绑定到不同的属性)。因此,请尝试将绑定到公共属性的 RadioButton 组合在它们自己的容器中,例如堆栈面板。如果您的相关 RadioButtons 无法共享单个父容器,则将每个 RadioButton 的 GroupName 属性设置为一个公共值以对它们进行逻辑分组。

编辑(2011 年 4 月 5 日):

简化 ConvertBack 的 if-else 以使用三元运算符。

注意 - 嵌套在类中的枚举类型(2011 年 4 月 28 日):

如果您的枚举类型嵌套在一个类中(而不是直接在命名空间中),您可以使用“+”语法访问 XAML 中的枚举,如对问题的(未标记)答案中所述:

ConverterParameter={x:Static local:YourClass+YourNestedEnumType.Enum1}

由于这个Microsoft Connect Issue,然而,VS2010 中的设计器将不再加载声明"Type 'local:YourClass+YourNestedEnumType' was not found.",但项目确实编译并成功运行。当然,如果您能够将枚举类型直接移动到命名空间,则可以避免此问题。


编辑(2012 年 1 月 27 日):

如果使用枚举标志,转换器将如下所示:
public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((Enum)value).HasFlag((Enum)parameter);
    }

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

编辑(2015 年 5 月 7 日):

在 Nullable Enum 的情况下(在问题中**没有**问,但在某些情况下可能需要,例如 ORM 从 DB 返回 null 或在程序逻辑中未提供值可能有意义的时候) ,请记住在 Convert 方法中添加初始 null 检查并返回适当的 bool 值,通常为 false(如果您不希望选择任何单选按钮),如下所示:
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) {
            return false; // or return parameter.Equals(YourEnumType.SomeDefaultValue);
        }
        return value.Equals(parameter);
    }

注意 - NullReferenceException(2018 年 10 月 10 日):

更新了示例以消除引发 NullReferenceException 的可能性。 `IsChecked` 是一个可为空的类型,因此返回 `Nullable` 似乎是一个合理的解决方案。

【讨论】:

  • 我同意,我相信这是一个更好的解决方案。此外,如果枚举值发生更改,使用这种转换将导致项目在编译时中断,而不是在运行时中断,这是一个很大的优势。
  • 这肯定是一个比公认的解决方案更好的解决方案。 +1
  • 不错的解决方案。我要补充一点,这实际上只是一个比较 2 个值的比较转换器。它可以有一个比 EnumToBooleanConverter 更通用的名称,例如 ComparisonConverter
  • @Scott,非常好。这个转换器在任何情况下都很好,有或没有标志属性。但是在大多数情况下,直接将此过滤器用作转换器并以枚举作为标志是很愚蠢的。原因是您应该使用先前的值实现布尔计算(|= 或 ^=)以获得正确的结果,但转换器无法访问先前的值。然后,您应该为每个枚举值添加一个布尔值,并在您的 MVVM 模型中自己进行正确的布尔计算。但是感谢您提供的所有信息,非常有用。
  • 在 Windows Phone 8 中(可能在 Win Store Apps 的情况下)我们没有 x:static,所以我们不能直接使用这里的解决方案。但是 IDE/Complier 足够聪明,可以根据所有字符串文字查找字符串(无论如何我的猜测)。例如这有效 驱动中的任何拼写错误都会在设计/编译时而不是运行时被捕获。
【解决方案2】:

您可以使用更通用的转换器

public class EnumBooleanConverter : IValueConverter
{
  #region IValueConverter Members
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
      return DependencyProperty.UnsetValue;

    if (Enum.IsDefined(value.GetType(), value) == false)
      return DependencyProperty.UnsetValue;

    object parameterValue = Enum.Parse(value.GetType(), parameterString);

    return parameterValue.Equals(value);
  }

  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
        return DependencyProperty.UnsetValue;

    return Enum.Parse(targetType, parameterString);
  }
  #endregion
}

在您使用的 XAML 部分中:

<Grid>
    <Grid.Resources>
      <l:EnumBooleanConverter x:Key="enumBooleanConverter" />
    </Grid.Resources>
    <StackPanel >
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FirstSelection}">first selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=TheOtherSelection}">the other selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=YetAnotherOne}">yet another one</RadioButton>
    </StackPanel>
</Grid>

【讨论】:

  • 对我来说就像一个魅力。作为补充,我修改了 ConvertBack 以在“false”上也返回 UnsetValue,因为 silverlight(可能是 WPF 正确)调用转换器两次 - 一次是在取消设置旧的单选按钮值时,然后再次设置新的值。我把其他东西挂在属性设置器上,所以我只希望它调用一次。 -- if (parameterString == null || value.Equals(false)) return DependencyProperty.UnsetValue;
  • 据我所知,这 必须 除非单选按钮位于不同的组中(并且默认情况下,没有设置 GroupName 且具有相同父级的 AFAIK 按钮在同一组)。否则,设置属性“反弹”的调用会导致奇怪的行为。
  • 是的,但是如果在设置为 false 时在转换器中调用 Unset,则它不是真正的 EnumToBooleanConverter,而是更多的 EnumToRadioButtonConverter。因此,我检查我的属性设置器中的值是否不同: if (_myEnumBackingField == value) return;
  • 此解决方案上的绑定只能单向正常工作。我无法通过将绑定属性分配给不同的值来以编程方式切换单选按钮。如果您想要一个正常工作且更好的解决方案,请使用 scott 的方法。
  • 重复上述说明:这不是两种方式。您不能设置属性并让单选按钮正确更改其 IsChecked。你真的很想使用 Scott 下面的方法。
【解决方案3】:

对于 EnumToBooleanConverter 答案: 如果单选按钮 IsChecked 的值变为 false,请考虑返回 Binding.DoNothing,而不是返回 DependencyProperty.UnsetValue。 前者表示存在问题(并且可能会向用户显示红色矩形或类似的验证指示符),而后者只是表示不应该做任何事情,这正是这种情况下想要做的。

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/library/system.windows.data.binding.donothing.aspx

【讨论】:

  • Silverlight 中没有 Binding.Nothing。它只是 WPF。请改用 null。
  • Binding.Nothing 也从 UWP 中消失了。
【解决方案4】:

我会在 ListBox 中使用 RadioButtons,然后绑定到 SelectedValue。

这是一个关于这个主题的旧帖子,但基本思想应该是相同的:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

【讨论】:

【解决方案5】:

对于 UWP 来说,就没有这么简单了:你必须跳过一个额外的箍来传递一个字段值作为参数。

示例 1

对 WPF 和 UWP 均有效。

<MyControl>
    <MyControl.MyProperty>
        <Binding Converter="{StaticResource EnumToBooleanConverter}" Path="AnotherProperty">
            <Binding.ConverterParameter>
                <MyLibrary:MyEnum>Field</MyLibrary:MyEnum>
            </Binding.ConverterParameter>
        </MyControl>
    </MyControl.MyProperty>
</MyControl>

示例 2

对 WPF 和 UWP 均有效。

...
<MyLibrary:MyEnum x:Key="MyEnumField">Field</MyLibrary:MyEnum>
...

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={StaticResource MyEnumField}}"/>

示例 3

仅对 WPF 有效!

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static MyLibrary:MyEnum.Field}}"/>

UWP 不支持x:Static,所以示例 3 是不可能的;假设你使用 Example 1,结果是更冗长的代码。 示例 2 稍好一些,但仍不理想。

解决方案

public abstract class EnumToBooleanConverter<TEnum> : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;

        if (Parameter == null)
            return DependencyProperty.UnsetValue;

        if (Enum.IsDefined(typeof(TEnum), value) == false)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(typeof(TEnum), Parameter).Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;
        return Parameter == null ? DependencyProperty.UnsetValue : Enum.Parse(typeof(TEnum), Parameter);
    }
}

然后,对于您希望支持的每种类型,定义一个封装枚举类型的转换器。

public class MyEnumToBooleanConverter : EnumToBooleanConverter<MyEnum>
{
    //Nothing to do!
}

之所以必须将其装箱是因为在ConvertBack 方法中似乎无法引用该类型;拳击会解决这个问题。如果您使用前两个示例中的任何一个,您可以只引用参数类型,从而无需从装箱类继承;如果您希望在一行中完成所有操作并且尽可能减少冗长,则后一种解决方案是理想的。

用法类似于示例 2,但实际上不那么冗长。

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>

缺点是您必须为希望支持的每种类型定义一个转换器。

【讨论】:

    【解决方案6】:

    我创建了一个新类来处理将 RadioButtons 和 CheckBoxes 绑定到枚举。它适用于标记枚举(具有多个复选框选择)和非标记枚举用于单选复选框或单选按钮。它也根本不需要 ValueConverters。

    一开始这可能看起来更复杂,但是,一旦你将这个类复制到你的项目中,它就完成了。它是通用的,因此可以轻松地用于任何枚举。

    public class EnumSelection<T> : INotifyPropertyChanged where T : struct, IComparable, IFormattable, IConvertible
    {
      private T value; // stored value of the Enum
      private bool isFlagged; // Enum uses flags?
      private bool canDeselect; // Can be deselected? (Radio buttons cannot deselect, checkboxes can)
      private T blankValue; // what is considered the "blank" value if it can be deselected?
    
      public EnumSelection(T value) : this(value, false, default(T)) { }
      public EnumSelection(T value, bool canDeselect) : this(value, canDeselect, default(T)) { }
      public EnumSelection(T value, T blankValue) : this(value, true, blankValue) { }
      public EnumSelection(T value, bool canDeselect, T blankValue)
      {
        if (!typeof(T).IsEnum) throw new ArgumentException($"{nameof(T)} must be an enum type"); // I really wish there was a way to constrain generic types to enums...
        isFlagged = typeof(T).IsDefined(typeof(FlagsAttribute), false);
    
        this.value = value;
        this.canDeselect = canDeselect;
        this.blankValue = blankValue;
      }
    
      public T Value
      {
        get { return value; }
        set 
        {
          if (this.value.Equals(value)) return;
          this.value = value;
          OnPropertyChanged();
          OnPropertyChanged("Item[]"); // Notify that the indexer property has changed
        }
      }
    
      [IndexerName("Item")]
      public bool this[T key]
      {
        get
        {
          int iKey = (int)(object)key;
          return isFlagged ? ((int)(object)value & iKey) == iKey : value.Equals(key);
        }
        set
        {
          if (isFlagged)
          {
            int iValue = (int)(object)this.value;
            int iKey = (int)(object)key;
    
            if (((iValue & iKey) == iKey) == value) return;
    
            if (value)
              Value = (T)(object)(iValue | iKey);
            else
              Value = (T)(object)(iValue & ~iKey);
          }
          else
          {
            if (this.value.Equals(key) == value) return;
            if (!value && !canDeselect) return;
    
            Value = value ? key : blankValue;
          }
        }
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
    
      private void OnPropertyChanged([CallerMemberName] string propertyName = "")
      {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }
    

    关于如何使用它,假设您有一个用于手动或自动运行任务的枚举,并且可以安排在一周中的任何一天,以及一些可选选项...

    public enum StartTask
    {
      Manual,
      Automatic
    }
    
    [Flags()]
    public enum DayOfWeek
    {
      Sunday = 1 << 0,
      Monday = 1 << 1,
      Tuesday = 1 << 2,
      Wednesday = 1 << 3,
      Thursday = 1 << 4,
      Friday = 1 << 5,
      Saturday = 1 << 6
    }
    
    public enum AdditionalOptions
    {
      None = 0,
      OptionA,
      OptionB
    }
    

    现在,使用这个类是多么容易:

    public class MyViewModel : ViewModelBase
    {
      public MyViewModel()
      {
        StartUp = new EnumSelection<StartTask>(StartTask.Manual);
        Days = new EnumSelection<DayOfWeek>(default(DayOfWeek));
        Options = new EnumSelection<AdditionalOptions>(AdditionalOptions.None, true, AdditionalOptions.None);
      }
    
      public EnumSelection<StartTask> StartUp { get; private set; }
      public EnumSelection<DayOfWeek> Days { get; private set; }
      public EnumSelection<AdditionalOptions> Options { get; private set; }
    }
    

    下面是用这个类绑定复选框和单选按钮是多么容易:

    <StackPanel Orientation="Vertical">
      <StackPanel Orientation="Horizontal">
        <!-- Using RadioButtons for exactly 1 selection behavior -->
        <RadioButton IsChecked="{Binding StartUp[Manual]}">Manual</RadioButton>
        <RadioButton IsChecked="{Binding StartUp[Automatic]}">Automatic</RadioButton>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <!-- Using CheckBoxes for 0 or Many selection behavior -->
        <CheckBox IsChecked="{Binding Days[Sunday]}">Sunday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Monday]}">Monday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Tuesday]}">Tuesday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Wednesday]}">Wednesday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Thursday]}">Thursday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Friday]}">Friday</CheckBox>
        <CheckBox IsChecked="{Binding Days[Saturday]}">Saturday</CheckBox>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <!-- Using CheckBoxes for 0 or 1 selection behavior -->
        <CheckBox IsChecked="{Binding Options[OptionA]}">Option A</CheckBox>
        <CheckBox IsChecked="{Binding Options[OptionB]}">Option B</CheckBox>
      </StackPanel>
    </StackPanel>
    
    1. 加载 UI 时,将选择“手动”单选按钮,您可以在“手动”或“自动”之间更改选择,但必须始终选择其中之一。
    2. 将取消选中一周中的每一天,但可以选中或取消选中任意数量的日期。
    3. “选项 A”和“选项 B”最初均未选中。您可以选中一个或另一个,选中一个将取消选中另一个(类似于 RadioButtons),但现在您也可以取消选中它们(使用 WPF 的 RadioButton 无法做到这一点,这就是此处使用 CheckBox 的原因)

    【讨论】:

    • 假设您在 StartTask 枚举中有 3 个项目,例如 { Undefined, Manual, Automatic } 您希望默认为 Undefined,因为在用户设置值之前它是未定义的。另外: SelectedItem 是如何处理的?您的 ViewModel 没有 SelectedStartTask。
    • 在我的 ViewModel 中,StartUp 属性是一个EnumSelection&lt;StartTask&gt; 对象。如果您查看EnumSelection&lt;T&gt; 的定义,您会发现它有一个Value 属性。所以视图模型不需要有“SelectedStartTask”。您将使用StartUp.Value。至于默认值为 Undefined,请参见第三个枚举 AdditionalOptions,它有一个 None 而不是 Undefined,但您可以将其名称更改为您想要的任何名称。
    【解决方案7】:

    这也适用于 Checkbox

    public class EnumToBoolConverter:IValueConverter
    {
        private int val;
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int intParam = (int)parameter;
            val = (int)value;
    
            return ((intParam & val) != 0);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            val ^= (int)parameter;
            return Enum.Parse(targetType, val.ToString());
        }
    }
    

    将单个枚举绑定到多个复选框。

    【讨论】:

    • 我非常感谢您对我的帮助。它对我来说就像一种魅力。
    【解决方案8】:

    您可以动态创建单选按钮,ListBox 可以帮助您做到这一点,无需转换器,非常简单。

    具体步骤如下:

    • 创建一个 ListBox 并将列表框的 ItemsSource 设置为枚举 MyLovelyEnum 并将 ListBox 的 SelectedItem 绑定到 VeryLovelyEnum 属性。
    • 然后将为每个 ListBoxItem 创建单选按钮。
    • 第 1 步:将枚举添加到 Window、UserControl 或 Grid 等的静态资源中。
        <Window.Resources>
            <ObjectDataProvider MethodName="GetValues"
                                ObjectType="{x:Type system:Enum}"
                                x:Key="MyLovelyEnum">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="local:MyLovelyEnum" />
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
        </Window.Resources>
    
    • 第 2 步:使用列表框和Control Template 将其中的每个项目填充为单选按钮
        <ListBox ItemsSource="{Binding Source={StaticResource MyLovelyEnum}}" SelectedItem="{Binding VeryLovelyEnum, Mode=TwoWay}" >
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}"
                                    IsChecked="{Binding Path=IsSelected,
                                    RelativeSource={RelativeSource TemplatedParent},
                                    Mode=TwoWay}" />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.Resources>
        </ListBox>
    

    优点是:如果有一天你的枚举类发生变化,你不需要更新 GUI(XAML 文件)。

    参考资料: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

    【讨论】:

    • 如果 EnumProperty 已经有值,这将不起作用。 public MyEnum EProperty {get; set;} = MyEnum.Value1。 RadioButton 没有被选中
    【解决方案9】:

    基于 Scott 的 EnumToBooleanConverter。 我注意到 ConvertBack 方法不适用于带有标志代码的枚举。

    我尝试了以下代码:

    public class EnumHasFlagToBooleanConverter : IValueConverter
        {
            private object _obj;
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                _obj = value;
                return ((Enum)value).HasFlag((Enum)parameter);
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value.Equals(true))
                {
                    if (((Enum)_obj).HasFlag((Enum)parameter))
                    {
                        // Do nothing
                        return Binding.DoNothing;
                    }
                    else
                    {
                        int i = (int)_obj;
                        int ii = (int)parameter;
                        int newInt = i+ii;
                        return (NavigationProjectDates)newInt;
                    }
                }
                else
                {
                    if (((Enum)_obj).HasFlag((Enum)parameter))
                    {
                        int i = (int)_obj;
                        int ii = (int)parameter;
                        int newInt = i-ii;
                        return (NavigationProjectDates)newInt;
    
                    }
                    else
                    {
                        // do nothing
                        return Binding.DoNothing;
                    }
                }
            }
        }
    

    我唯一不能开始工作的就是从int 转换为targetType,所以我将其硬编码为NavigationProjectDates,即我使用的枚举。还有,targetType == NavigationProjectDates...


    编辑更通用的标志枚举转换器:

    公共类FlagsEnumToBooleanConverter:IValueConverter { 私人 int _flags=0; public object Convert(object value, Type targetType, object parameter, string language) { 如果(值 == 空)返回假; _flags = (int) 值; 类型 t = value.GetType(); 对象 o = Enum.ToObject(t, 参数); return ((Enum)value).HasFlag((Enum)o); } public object ConvertBack(object value, Type targetType, object parameter, string language) { if (value?.Equals(true) ?? false) { _flags = _flags | (int) 参数; } 别的 { _flags = _flags & ~(int) 参数; } 返回_flags; } }

    【讨论】:

    • 有人编辑了我的答案以添加到 with Flags 代码中,所以老实说,我自己从未尝试/使用过它,并且考虑过删除它,因为我认为它作为自己的答案更有意义。如果我以后能找到一些时间,我可以尝试将一些东西放在一起来测试该代码以及您拥有的代码,也许有助于为您的问题找到更好的解决方案。
    【解决方案10】:

    使用 Nullable 的 UWP 双向绑定解决方案:

    C#部分:

    public class EnumConverter : IValueConverter
    {
        public Type EnumType { get; set; }
        public object Convert(object value, Type targetType, object parameter, string lang)
        {
            if (parameter is string enumString)
            {
                if (!Enum.IsDefined(EnumType, value)) throw new ArgumentException("value must be an Enum!");
                var enumValue = Enum.Parse(EnumType, enumString);
                return enumValue.Equals(value);
            }
            return value.Equals(Enum.ToObject(EnumType,parameter));
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string lang)
        {
            if (parameter is string enumString)
                return value?.Equals(true) == true ? Enum.Parse(EnumType, enumString) : null;
            return value?.Equals(true) == true ? Enum.ToObject(EnumType, parameter) : null;
        }
    }
    

    这里 null 值充当 Binding.DoNothing。

    private YourEnum? _yourEnum = YourEnum.YourDefaultValue; //put a default value here
    public YourEnum? YourProperty
    {
        get => _yourEnum;
        set{
            if (value == null) return;
            _yourEnum = value;
        }
    }
    

    Xaml 部分:

    ...
    <Page.Resources>
        <ResourceDictionary>
            <helper:EnumConverter x:Key="YourConverter" EnumType="yournamespace:YourEnum" />
        </ResourceDictionary>
    </Page.Resources>
    ...
    <RadioButton GroupName="YourGroupName" IsChecked="{Binding Converter={StaticResource YourConverter}, Mode=TwoWay, Path=YourProperty, ConverterParameter=YourEnumString}">
        First way (parameter of type string)
    </RadioButton>
    <RadioButton GroupName="LineWidth">
        <RadioButton.IsChecked>
            <Binding
                Converter="{StaticResource PenWidthConverter}"
                Mode="TwoWay"   Path="PenWidth">
                <Binding.ConverterParameter>
                    <yournamespace:YourEnum>YourEnumString</yournamespace:YourEnum>
                </Binding.ConverterParameter>
            </Binding>
        </RadioButton.IsChecked>
        Second way (parameter of type YourEnum (actually it was converted to int when passed to converter))
    </RadioButton>
    

    【讨论】:

      【解决方案11】:

      处理此问题的一种方法是在 ViewModel 类中使用单独的 bool 属性。以下是我处理这种情况的方法:

      视图模型:

      public enum MyLovelyEnum { FirstSelection, TheOtherSelection, YetAnotherOne };
      private MyLovelyEnum CurrentSelection;
      
      public bool FirstSelectionProperty
      {
          get
          {
              return CurrentSelection == MyLovelyEnum.FirstSelection;
          }
          set
          {
              if (value)
                  CurrentSelection = MyLovelyEnum.FirstSelection;
          }
      }
      
      public bool TheOtherSelectionProperty
      {
          get
          {
              return CurrentSelection == MyLovelyEnum.TheOtherSelection;
          }
          set
          {
              if (value)
                  CurrentSelection = MyLovelyEnum.TheOtherSelection;
          }
      }
      
      public bool YetAnotherOneSelectionProperty
      {
          get
          {
              return CurrentSelection == MyLovelyEnum.YetAnotherOne;
          }
          set
          {
              if (value)
                  CurrentSelection = MyLovelyEnum.YetAnotherOne;
          }
      }
      

      XAML:

      <RadioButton IsChecked="{Binding SimilaritySort, Mode=TwoWay}">Similarity</RadioButton>
      <RadioButton IsChecked="{Binding DateInsertedSort, Mode=TwoWay}">Date Inserted</RadioButton>
      <RadioButton IsChecked="{Binding DateOfQuestionSort, Mode=TwoWay}">Date of Question</RadioButton>
      <RadioButton IsChecked="{Binding DateModifiedSort, Mode=TwoWay}">Date Modified</RadioButton>
      

      它不像其他一些解决方案那样健壮或动态,但好处是它非常独立,不需要创建自定义转换器或类似的东西。

      【讨论】:

        猜你喜欢
        • 2011-03-16
        • 1970-01-01
        • 2011-12-21
        • 2015-10-17
        • 1970-01-01
        • 1970-01-01
        • 2011-08-04
        • 1970-01-01
        相关资源
        最近更新 更多