我喜欢使用依赖对象将我的组合框与enum绑定。我搜索并发现这个解决方案非常适合MVVM,
我的xaml是
<ComboBox SelectedItem="{Binding Color,Mode=TwoWay}"
l:EnumHelper.Enum="{x:Type l:MyEnum }"></ComboBox>
我的依赖对象是
public class EnumHelper : DependencyObject
{
public static Type GetEnum(DependencyObject obj)
{
return (Type)obj.GetValue(EnumProperty);
}
public static void SetEnum(DependencyObject obj, string value)
{
obj.SetValue(EnumProperty, value);
}
// Using a DependencyProperty as the backing store for Enum. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnumProperty =
DependencyProperty.RegisterAttached("Enum", typeof(Type), typeof(EnumHelper), new PropertyMetadata(null, OnEnumChanged));
private static void OnEnumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as ItemsControl;
if (control != null)
{
if (e.NewValue != null)
{
var _enum = Enum.GetValues(e.NewValue as Type);
control.ItemsSource = _enum;
}
}
}
}
我想知道我是否必须阅读枚举描述并使用依赖对象将其转换回来,我该如何扩展这个助手类。
答案 0 :(得分:1)
我使用MarkupExtension
而不是附加属性的方法略有不同:
public sealed class EnumValues : MarkupExtension
{
private readonly Type _enumType;
public EnumValues(Type enumType)
{
_enumType = enumType;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Enum.GetValues(_enumType);
}
}
我发现它更优雅,因为它更短,我可以写ItemsSource="{l:EnumValues {l:MyEnum}}"
。
对于枚举值描述,我使用转换器:
public sealed class EnumValueToDecriptionConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return null;
}
var type = value.GetType();
if(!type.IsEnum)
{
return null;
}
var field = type.GetField(value.ToString());
var attr = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
.Cast<DescriptionAttribute>()
.FirstOrDefault();
if(attr != null)
{
return attr.Description;
}
else
{
return field.Name;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
所以最后你可以在XAML中写这个:
<ComboBox SelectedItem="{Binding Color, Mode=TwoWay}"
ItemsSource="{l:EnumValues {x:Type l:MyEnum}}">
<FrameworkElement.Resources>
<l:EnumValueToDecriptionConverter x:Key="EnumValueToDecriptionConverter" />
</FrameworkElement.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Mode=OneTime,
Converter={StaticResource EnumValueToDecriptionConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
如果您需要多次,可以在应用程序级别将此DataTemplate
定义为资源。
答案 1 :(得分:1)
为了减少重复代码,我使用自定义控件:
以下是自定义EnumComboBox控件的用法:
<myCustomControls:EnumComboBox
EnumType="{x:Type myEnums:MyEnumType}"
SelectedEnumValue="{Binding MyBindingProperty}"/>
EnumComboBox只是从ComboBox继承而来:(EnumComboBox.xaml)
<ComboBox x:Class="MyProject.MyCustomControls.EnumComboBox" />
EnumComboBox.xaml.cs:
public partial class EnumComboBox
{
public EnumComboBox()
{
InitializeComponent();
}
public Type EnumType
{
get { return (Type)GetValue(EnumTypeProperty); }
set { SetValue(EnumTypeProperty, value); }
}
public Enum SelectedEnumValue
{
get { return (Enum)GetValue(SelectedEnumValueProperty); }
set { SetValue(SelectedEnumValueProperty, value); }
}
public static readonly DependencyProperty EnumTypeProperty =
DependencyProperty.Register("EnumType", typeof(Type), typeof(EnumComboBox), new UIPropertyMetadata(null));
public static readonly DependencyProperty SelectedEnumValueProperty =
DependencyProperty.Register("SelectedEnumValue", typeof(Enum), typeof(EnumComboBox), new UIPropertyMetadata(null));
private readonly Dictionary<string, Enum> _conversionDictionary = new Dictionary<string, Enum>();
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == EnumTypeProperty)
{
foreach (var en in Enum.GetValues(EnumType))
{
var descr = Description((Enum)en);
_conversionDictionary.Add(descr, (Enum)en);
}
ItemsSource = _conversionDictionary.Keys.OrderBy(x => x);
}
else if (e.Property == SelectedItemProperty)
{
SelectedEnumValue = _conversionDictionary[e.NewValue.ToString()];
}
else if (e.Property == SelectedEnumValueProperty)
{
SetValue(SelectedItemProperty, Description((Enum)e.NewValue));
}
base.OnPropertyChanged(e);
}
public static string Description(Enum value)
{
if (value == null)
return null;
var enumType = value.GetType();
var field = enumType.GetField(value.ToString());
if (field == null)
return null;
var attr = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
.Cast<DescriptionAttribute>()
.FirstOrDefault();
return attr == null ? value.ToString() : attr.Description;
}
}
这只是我的首选方式,并希望分享它以防其他人想要使用它。 特别是因为花了一段时间才弄明白:)