Yes, by the time you pass the value into the converter it will be a string
as the default type converter for Enum (EnumConverter) for GetStandardValues
(i.e. Enum.GetValues()
) returns an enumerable of the fields as strings.
The best way to solve this to write a custom type converter to decorate your Enums with. Fortunately you are not the first person that has needed to this, see below for code sample.
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);
}
}
Usage
[TypeConverter(typeof(EnumTypeConverter))]
public enum UserTypes : int
{
[Browsable(false)]
Unkown,
[Description("Local")]
LocalUser,
[Description("Network")]
NetworkUser,
[Description("Restricted")]
RestrictedUser
}
As you can see, the above enum we have used the Description
attribute to decorate each field with a user friend description and have overridden the type converter to first look for this attribute.
Not 100% but to get this to work with your code, you will also need to change your MarkupExtension
to be the following (Note: I have not tested this, so some work on your part is required).
[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);
}
}
Also, I have only done limited localisation for an application however I believe this is the best and most maintainable approach as will be able to leverage the existing .NET localisation tools (e.g. satellite assemblies)