如何将RadioButtons绑定到一个枚举?
我有这样的枚举:
public enum MyLovelyEnum { FirstSelection, TheOtherSelection, YetAnotherOne };
我在我的DataContext中有一个属性:
public MyLovelyEnum VeryLovelyEnum { get; set; }
我的WPF客户端中有三个RadioButton。
<RadioButton Margin="3">First Selection</RadioButton> <RadioButton Margin="3">The Other Selection</RadioButton> <RadioButton Margin="3">Yet Another one</RadioButton>
现在我该如何将RadioButtons绑定到该属性以进行正确的双向绑定?
你可以使用更通用的转换器
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-Part中:
<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>
您可以进一步简化接受的答案。 而不是在xaml中input枚举string,并在转换器中进行更多的工作,而不是使用string表示forms。而CrimsonX评论道,在编译时抛出错误,而不是运行时:
ConverterParameter = {x:静态本地:YourEnumType.Enum1}
<StackPanel> <StackPanel.Resources> <local:EnumToBooleanConverter x:Key="EnumToBooleanConverter" /> </StackPanel.Resources> <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" /> <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" /> </StackPanel>
然后简化转换器:
public class EnumToBooleanConverter : 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) ? parameter : Binding.DoNothing; } }
注 – 在同一个容器中的多个RadioButton组(11年2月17日):
在xaml中,如果单选button共享同一个父容器,则select其中一个将取消select该容器中的所有其他容器(即使它们绑定到不同的属性)。 因此,尽量保持你的RadioButton的绑定到一个共同的属性组合在他们自己的容器像堆栈面板。 在您的相关RadioButtons不能共享一个父容器的情况下,然后将每个RadioButton的GroupName属性设置为一个公共值,以便对它们进行逻辑分组。
注 – 嵌套在类中的枚举types(11年4月28日):
如果枚举types嵌套在类中(而不是直接嵌套在名称空间中),则可能可以使用“+”语法来访问XAML中的枚举,如(无标记的)对无法find的问题的回答中所述WPF中静态引用的枚举types :
ConverterParameter = {x:静态本地: YourClass + YourNestedEnumType.Enum1}
但是,由于此Microsoft连接问题 ,VS2010中的devise器将不再加载说明"Type 'local:YourClass+YourNestedEnumType' was not found."
,但项目编译并运行成功。 当然,如果可以直接将枚举types移动到名称空间,则可以避免此问题。
编辑(十二月16 '10):
感谢匿名提示返回Binding.DoNothing而不是DependencyProperty.UnsetValue。
编辑(4月5 '11):
简化的ConvertBack的if-else使用三元运算符。
编辑(1月27 '12):
如果使用枚举标志,转换器将如下所示:
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; } }
编辑(15年5月7日):
在Numlable Enum的情况下(在问题中没有被问到,但在某些情况下可能需要,例如ORM从DB返回null,或者只要在程序逻辑中没有提供值就可以),请记得添加在转换方法中初始空检查并返回适当的布尔值,通常是false(如果你不想要任何单选button),如下所示:
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); }
对于EnumToBooleanConverter答案:而不是返回DependencyProperty.UnsetValue考虑返回Binding.DoNothing单选buttonIsChecked值变为false的情况下。 前者表示一个问题(可能会向用户显示一个红色的矩形或类似的validation指标),而后者则表明不应该做任何事情,这就是在这种情况下所要做的。
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
我将使用ListBox中的RadioButtons,然后绑定到SelectedValue。
这是一个关于这个主题的旧线程,但基本思路应该是一样的: http : //social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/
通过将单选button绑定到任何types(枚举,布尔,string,整数等)的能力,扩展了以上伟大的想法,并提供了工作示例代码:
http://www.codeproject.com/Tips/720497/Binding-Radio-Buttons-to-a-Single-Property
对于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是不可能的; 假设你去例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); } }
然后,对于您希望支持的每种types,请定义一个转换器来将枚举types框起来。
public class MyEnumToBooleanConverter : EnumToBooleanConverter<MyEnum> { //Nothing to do! }
必须装盒的原因是因为似乎没有办法在ConvertBack
方法中引用types; 拳击照顾。 如果使用前两个示例中的任何一个,则只需引用参数types即可,无需从盒装类inheritance。 如果你希望以一行的方式完成所有工作,并且可能性最小,那么后一种解决scheme是理想的。
用法类似于示例2 ,但事实上不太详细。
<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>
缺点是你必须为你想支持的每种types定义一个转换器。
基于Scott的EnumToBooleanConverter。 我注意到ConvertBack方法不能用Enum和flags代码工作。
我试过下面的代码:
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
进行targetType
所以我将其硬编码为NavigationProjectDates
(我使用的枚举)。 而且, targetType == NavigationProjectDates
…
编辑更多通用标志枚举转换器:
公共类FlagsEnumToBooleanConverter:IValueConverter { private int _flags = 0; 公共对象Convert(对象值,typestargetType,对象参数,string语言){ if(value == null)返回false; _flags =(int)值; typest = value.GetType(); object o = Enum.ToObject(t,parameter); 返回((Enum)值).HasFlag((Enum)o); } 公共对象ConvertBack(对象值,typestargetType,对象参数,string语言) { if(value?.Equals(true)?? false){ _flags = _flags | (int)参数; } else { _flags = _flags&〜(int)参数; } return _flags; } }