我有一个基于 C# MVVM Light 的应用程序,它有几个枚举属性。我厌倦了编写管道代码来支持它们。通常,我编写的管道代码是成对字符串属性的形式,或者有时是类型特定的值转换器,以促进数据绑定到枚举属性。我怎样才能做到这一点,而无需编写额外的代码来将数据绑定的 UI 元素连接到枚举属性?
问问题
158 次
1 回答
1
我做了一些挖掘和试验,现在我有一个用于任何 ViewModel 枚举属性的值转换器,它在枚举值的描述属性字符串和它们表示的枚举常量之间进行双向转换。这允许您将双向数据绑定到枚举属性,而无需执行任何管道代码。您唯一需要做的就是将绑定属性的 Enumeration 类型的完全限定类型名称放在ConverterParameter字段中(示例见下图)。如果您在确定正确的完全限定的 Enum 类型名称时遇到问题,只需在ConvertBack()中设置一个断点,将抛出异常。然后打电话System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes.ToList()以获取该执行上下文中所有当前定义的系统类型的列表。找到正确的完全限定类型名称并将其粘贴到ConverterParameter字段中。
- 使用ToDescriptionsList<>()方便地从Enum类型中获取 Description 属性以填充列表框或其他元素。将对它的调用放在属性中,该属性将人类友好的字符串列表返回到绑定到枚举属性的 UI 元素。(例如,列表框的ItemsSource属性)。
具有描述属性的枚举类型示例:
// (barnyard, bird, cat, dog, horse, pig, reptile, smallfurry)
// List of Animal types the breed list method accepts.
public enum EnumAnimalType
{
[Description("Barnyard")]
barnyard,
[Description("Birds")]
bird,
[Description("Cats & Kittens")]
cat,
[Description("Dogs & Puppies")]
dog,
[Description("Horses & Ponies")]
horse,
[Description("Pigs")]
pig,
[Description("Reptiles")]
reptile,
[Description("Other Small & Furry")]
smallfurry
}
// Value converter class that does the conversion work.
public class EnumToDescAttrConverter : IValueConverter
{
// Derived Grant Barrintgon's blog on C#.
/// <summary>
/// Extension method that retrieves the description attribute for a particular enum value.
/// [Description("Bright Pink")]
/// BrightPink = 2,
/// </summary>
/// <param name="en">The Enumeration</param>
/// <returns>A string representing the friendly name</returns>
public 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;
}
// Unable to find a description attribute for the enum. Just return the
// value of the ToString() method.
return en.ToString();
}
// Consumer wants to convert an enum to a description attribute string.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Since we don't know what the correct default value should be, a NULL value is unacceptable.
if (value == null)
throw new ArgumentNullException("(EnumToDescAttrConverter:Convert) The value is unassigned.");
Enum e = (Enum)value;
return e.GetDescription();
} // public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
// Convert an enumeration value in Description attribute form back to the appropriate enum value.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Since we don't know what the correct default value should be, a NULL value is unacceptable.
if (value == null)
throw new ArgumentNullException("(EnumToDescAttrConverter:ConvertBack) The value is unassigned.");
string strValue = (string)value;
// Parameter parameter must be set since it must contain the concrete Enum class name.
if (parameter == null)
throw new ArgumentNullException("(EnumToDescAttrConverter:ConvertBack) The Parameter parameter is unassigned.");
string theEnumClassName = parameter.ToString();
// Create an instance of the concrete enumeration class from the given class name.
Enum e = (Enum)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(theEnumClassName);
if (e == null)
throw new ArgumentException(
"(EnumToDescAttrConverter:ConvertBack) Invalid enumeration class name: " + theEnumClassName
+ ". Set a break point here and call System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes.ToList()"
+ " in the immediate window to find the right type. Put that type into the Converter parameter for the"
+ " data bound element you are working with."
);
System.Type theEnumType = e.GetType();
Enum eRet = null;
foreach (MemberInfo memInfo in theEnumType.GetMembers())
{
object[] attrs = memInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
if (((DescriptionAttribute)attrs[0]).Description == strValue)
{
// Ignore the case
eRet = (Enum)Enum.Parse(theEnumType, memInfo.Name, true);
break; // Found it.
}
}
} // foreach (MemberInfo memInfo in typeof(TEnum).GetMembers())
// If the string can not be converted to a valid enum value, throw an
// Exception.
if (eRet == null)
throw new ArgumentException(String.Format("{0} can not be converted to an enum value: ", strValue));
return eRet;
} // public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
/// <summary>
/// Returns all the values for given Enum as a list of their string attributes. <br />
/// Use this method to fill a list box with human friendly strings for each <br />
/// enumeration value using the DescriptionAttribute() associated it/them.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>An enumerator for the Enum values</returns>
public static List<string> ToDescriptionsList<T>()
{
// GetValues() is not available on Windows Phone.
// return Enum.GetValues(typeof(T)).Cast<T>();
List<string> listRet = new List<string>();
foreach (var x in typeof(T).GetFields())
{
Enum e;
if (x.IsLiteral)
{
e = (Enum)x.GetValue(typeof(Enum));
listRet.Add(e.GetDescription());
} // if (x.IsLiteral)
} // foreach()
return listRet;
} // public static IEnumerable<T> GetValues<T>(this T theEnum) } // public class EnumToDescAttrConverter : IValueConverter
} // public class EnumToDescAttrConverter : IValueConverter
于 2013-04-21T02:21:51.950 回答