转换器显示枚举的描述,并在从wpf的combobox中选择项目时转换回枚举值
我正在使用枚举来在我的combobox中登记值。 我想写一个转换器,它将显示所选枚举值的“描述”。 并且,选中后,它将返回枚举值。
大多数在线转换器都没有实现ConvertBack()方法(这就是我在这里发布的原因)。
提前致谢。
这是ConvertBack方法:
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; }
完整转换器代码:
public class EnumConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) return DependencyProperty.UnsetValue; return GetDescription((Enum)value); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; } public static string GetDescription(Enum en) { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); if (attrs != null && attrs.Length > 0) { return ((DescriptionAttribute)attrs[0]).Description; } } return en.ToString(); } }
编辑
这是我的ComboBox XAML:
编辑2:
我最初有一个不正确的XAML,我将SelectedValue
绑定到ComboBox.SelectedIndex
,而不是ComboBox.SelectedItem
。 这就是我必须在ConvertBack
方法中使用Enum.ToObject
的原因。 在修复XAML并通过调试器运行示例后,我意识到我只能从ConvertBack
方法返回value
,因此值本身是Enum
类型。
我知道这是一个老问题,但由于某种原因,这是相当复杂的,即使它似乎是一个非常常见的任务(我目前在UWP应用程序上这样做)。 结合已接受的答案,我发现的其他一些项目,以及我自己的一些工作,这是我发现完成这项琐事的最简单方法。 简而言之:
- 定义您的枚举沿着/在Display属性中设置描述
- 创建一个从枚举值转换为描述的转换器
- 在viewmodel中,公开要从中选择的枚举值的集合,所选的枚举值,然后初始化它们
- 定义一些方便的枚举扩展方法
- 最后,一些简单的绑定到ComboBox,只是覆盖其ItemTemplate以使用转换器。
枚举
public enum EnumOptions { [Display(Description = "Option 1")] OptionOne= 1, [Display(Description = "Option 2")] OptionTwo, [Display(Description = "Option 3")] OptionThree }
变流器
public class EnumToDisplayConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { var enumValue = value as Enum; return enumValue == null ? DependencyProperty.UnsetValue : enumValue.GetDescriptionFromEnumValue(); } public object ConvertBack(object value, Type targetType, object parameter, string language) { return value; } }
Viewmodel(部分)
public IReadOnlyList Options { get; } private EnumOptions _selectedOption; public EnumOptions SelectedOption { get { return _selectedOption; } set { _selectedOption = value; OnPropertyChanged(() => SelectedOption); } } // Initialization in constructor Options = EnumExtensions.GetValues ().ToArray(); // If you want to set a default. SelectedOption = Options[0];
扩展
public static class EnumExtensions { public static string GetDescriptionFromEnumValue(this Enum value) { var attribute = value.GetType() .GetField(value.ToString()) .GetCustomAttributes(typeof(DisplayAttribute), false) .SingleOrDefault() as DisplayAttribute; return attribute == null ? value.ToString() : attribute.Description; } /// /// Enumerates all enum values /// /// Enum type /// IEnumerable containing all enum values /// public static IEnumerable GetValues () { return Enum.GetValues(typeof (T)).Cast (); } }
XAML(部分)
Choose an option
[ValueConversion(typeof(MyEnum), typeof(String))] public class MyEnumConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var enumVal = (MyEnum)value; // in this example, this is an extension method return enumValue.Description(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var enumDesc = value as string; MyEnum val; if (Enum.TryParse(typeof(MyEnum), strValue, out val)) { return val; } return DependencyProperty.UnsetValue; } }
示例中的扩展方法可能如下所示:
public static string Description(this MyEnum enumVal) { // you could use a switch statement here; // or maybe a Dictionary }
以上示例的补充,以显示使用属性装饰枚举。
sealed class DescriptionAttribute : Attribute { readonly string description; public DescriptionAttribute(string description) { this.description = description; } public string Description { get { return description; } } } enum Vehicle { [Description("Benz")] Car, [Description("Volvo")] Bus, [Description("Honda")] Bike }
顺便说一句,我想知道为什么你需要将描述转换回enum。 如果您将枚举本身作为ItemSource提供,则可以使用描述技术在ComboBox中显示显示值,但是,一旦选择了某个项目,您就可以直接将枚举作为所选项目。
这是我工作良好的例子:
枚举定义:
public enum MyEnum { [Description("Exchange 2007")] E2007, [Description("Exchange 2010")] E2010, [Description("Exchange 2013")] E2013, };
助手class:
public static class cHelperClass { #region GetValuesAndDescriptions public static object[] GetValuesAndDescriptions(Type enumType) { var kvPairList = new List>(); var listValue = Enum.GetValues(enumType); for (var i = 0; i < listValue.Length; i++) { var value = listValue.GetValue(i); var enumValue = (Enum)listValue.GetValue(i); kvPairList.Add(new KeyValuePair(value.ToString(), GetDescription(enumValue))); } var valuesAndDescriptions = from kv in kvPairList select new { Value = kv.Key, Description = kv.Value }; return valuesAndDescriptions.ToArray(); } public static string GetDescription(this Enum value) { var fieldInfo = value.GetType().GetField(value.ToString()); var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); return (attributes.Length > 0) ? attributes[0].Description : value.ToString(); } public static string GetStringValue(this Enum enumItem) { return enumItem .GetType() .GetField(enumItem.ToString()) .GetCustomAttributes() .Select(a => a.Value) .FirstOrDefault() ?? enumItem.ToString(); } public static string GetName(Type enumType, object value) { return Enum.GetName(enumType, value); } #endregion }
XAML: