いくつかの列挙されたプロパティを持つ C# MVVM Light ベースのアプリケーションがあります。それらをサポートするための配管コードを書くのにうんざりしています。通常、私が作成する配管コードは、ペアになった文字列プロパティの形をしているか、列挙されたプロパティへのデータ バインディングを容易にするために型固有の値コンバーターの形をとっています。データ バインドされた UI 要素を列挙されたプロパティにブリッジするためだけに、追加のコードを記述せずにこれを行うにはどうすればよいでしょうか?
1 に答える
1
少し掘り下げて実験した結果、列挙値の説明属性文字列とそれらが表す列挙定数との間で双方向の変換を行う、ViewModel 列挙プロパティの値コンバーターができました。これにより、配管コードを実行しなくても、列挙型プロパティに双方向のデータ バインドを実行できます。バインドされたプロパティの列挙型の完全修飾型名を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 に答える