C# 使用组合框MVVM绑定枚举描述
Hi Iam使用依赖项对象将我的combobox与enum绑定。我搜索并发现这个解决方案对于MVVM非常优雅 我的xaml是C# 使用组合框MVVM绑定枚举描述,c#,wpf,mvvm,dependency-properties,C#,Wpf,Mvvm,Dependency Properties,Hi Iam使用依赖项对象将我的combobox与enum绑定。我搜索并发现这个解决方案对于MVVM非常优雅 我的xaml是 <ComboBox SelectedItem="{Binding Color,Mode=TwoWay}" l:EnumHelper.Enum="{x:Type l:MyEnum }"></ComboBox> 我想知道,如果我必须阅读枚举描述并使用dependency object将其转换回,我如何扩展此h
<ComboBox SelectedItem="{Binding Color,Mode=TwoWay}"
l:EnumHelper.Enum="{x:Type l:MyEnum }"></ComboBox>
我想知道,如果我必须阅读枚举描述并使用dependency object将其转换回,我如何扩展此helper类。我使用与
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
}
公共密封类EnumValueToDecriptionConverter:IValueConverter
{
#区域转换器成员
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
如果(值==null)
{
返回null;
}
var type=value.GetType();
如果(!type.IsEnum)
{
返回null;
}
var field=type.GetField(value.ToString());
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
如果(attr!=null)
{
返回属性描述;
}
其他的
{
返回字段名称;
}
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException();
}
#端区
}
最后,您可以用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>
如果您多次需要此数据模板,可以将其定义为应用程序级别的资源。我对标记扩展使用稍微不同的方法,而不是附加属性:
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
}
公共密封类EnumValueToDecriptionConverter:IValueConverter
{
#区域转换器成员
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
如果(值==null)
{
返回null;
}
var type=value.GetType();
如果(!type.IsEnum)
{
返回null;
}
var field=type.GetField(value.ToString());
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
如果(attr!=null)
{
返回属性描述;
}
其他的
{
返回字段名称;
}
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException();
}
#端区
}
最后,您可以用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>
如果您多次需要此数据模板,可以将其定义为应用程序级别的资源。为了减少重复代码,我使用了一个自定义控件:
以下是自定义EnumComboBox控件的用法:
EnumComboBox只是从组合框继承,如下所示:(EnumComboBox.xaml)
EnumComboBox.xaml.cs:
公共部分类枚举组合框
{
公共枚举组合框()
{
初始化组件();
}
公共类型枚举类型
{
get{return(Type)GetValue(EnumTypeProperty);}
set{SetValue(EnumTypeProperty,value);}
}
公共枚举SelectedEnumValue
{
获取{return(Enum)GetValue(SelectedEnumValueProperty);}
set{SetValue(selectedUnmValueProperty,value);}
}
公共静态只读DependencyProperty EnumTypeProperty=
Register(“EnumType”、typeof(Type)、typeof(EnumComboBox)、newUIPropertyMetadata(null));
公共静态只读从属属性SelectedEnumValueProperty=
Register(“SelectedEnumValue”、typeof(Enum)、typeof(EnumComboBox)、new-UIPropertyMetadata(null));
专用只读词典_conversionDictionary=新词典();
受保护的重写无效OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if(e.Property==EnumTypeProperty)
{
foreach(Enum.GetValues(EnumType)中的var en)
{
var descr=描述((枚举)en);
_conversionDictionary.Add(descr,(Enum)en);
}
ItemsSource=\u conversionDictionary.Keys.OrderBy(x=>x);
}
else if(e.Property==SelectedItemProperty)
{
SelectedEnumValue=_conversionDictionary[e.NewValue.ToString()];
}
else if(e.Property==selectedUnmValueProperty)
{
SetValue(SelectedItemProperty,Description((Enum)e.NewValue));
}
根据改变的财产(e);
}
公共静态字符串描述(枚举值)
{
如果(值==null)
返回null;
var enumType=value.GetType();
var field=enumType.GetField(value.ToString());
如果(字段==null)
返回null;
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
返回attr==null?value.ToString():attr.Description;
}
}
这正是我喜欢的方式,我想分享它,以防其他人想使用它。
特别是因为我花了一段时间才弄明白:)为了减少重复代码,我使用了一个自定义控件:
以下是自定义EnumComboBox控件的用法:
EnumComboBox只是从这样的ComboBox继承:
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;
}
}