はい、値をコンバーターに渡すときまでに、string
列挙型(EnumConverter)のデフォルトの型コンバーターとしてGetStandardValues
(つまりEnum.GetValues()
)フィールドの列挙型を文字列として返します。
これを解決する最良の方法は、列挙型を装飾するカスタム型コンバーターを作成することです。幸い、これを必要としたのはあなたが最初ではありません。コードサンプルについては以下を参照してください。
public class EnumTypeConverter : EnumConverter
{
public EnumTypeConverter()
: base(typeof(Enum))
{
}
public EnumTypeConverter(Type type)
: base(type)
{
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || TypeDescriptor.GetConverter(typeof(Enum)).CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
return GetEnumValue(EnumType, (string)value);
if (value is Enum)
return GetEnumDescription((Enum)value);
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is Enum && destinationType == typeof(string))
return GetEnumDescription((Enum)value);
if (value is string && destinationType == typeof(string))
return GetEnumDescription(EnumType, (string)value);
return base.ConvertTo(context, culture, value, destinationType);
}
public static bool GetIsEnumBrowsable(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var attributes = (BrowsableAttribute[])fieldInfo.GetCustomAttributes(typeof(BrowsableAttribute), false);
return !(attributes.Length > 0) || attributes[0].Browsable;
}
public static string GetEnumDescription(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 GetEnumDescription(Type value, string name)
{
var fieldInfo = value.GetField(name);
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? attributes[0].Description : name;
}
public static object GetEnumValue(Type value, string description)
{
var fields = value.GetFields();
foreach (var fieldInfo in fields)
{
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0 && attributes[0].Description == description)
return fieldInfo.GetValue(fieldInfo.Name);
if (fieldInfo.Name == description)
return fieldInfo.GetValue(fieldInfo.Name);
}
return description;
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return base.GetStandardValues(context);
}
}
使用法
[TypeConverter(typeof(EnumTypeConverter))]
public enum UserTypes : int
{
[Browsable(false)]
Unkown,
[Description("Local")]
LocalUser,
[Description("Network")]
NetworkUser,
[Description("Restricted")]
RestrictedUser
}
ご覧のとおり、上記の列挙型では、Description
属性を使用して各フィールドをユーザーフレンドの説明で装飾し、タイプコンバーターをオーバーライドして最初にこの属性を探しました。
100%ではありませんが、これをコードで機能させるMarkupExtension
には、次のように変更する必要もあります(注:これはテストしていないため、ユーザー側でいくつかの作業が必要です)。
[MarkupExtensionReturnType(typeof (IEnumerable))]
public class EnumValuesExtension : MarkupExtension {
public EnumValuesExtension() {}
public EnumValuesExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.EnumType == null)
throw new ArgumentException("The enum type is not set");
var converter = TypeDescriptor.GetConverter(this.EnumType);
if (converter != null && converter.GetStandardValuesSupported(this.EnumType))
return converter.GetStandardValues(this.EnumType);
return Enum.GetValues(this.EnumType);
}
}
また、アプリケーションのローカリゼーションは限られていますが、既存の.NETローカリゼーションツール(衛星アセンブリなど)を活用できるため、これが最良で最も保守しやすいアプローチであると思います。