I am using an enum to enlist values in my combobox. I want to write a converter that would show the "description" of the selected enum value. And, when selected, i
I know this is an old question, but for some reason, this is rather complicated, even though it seems like it'd be a pretty common task (I'm currently doing this on a UWP app). Using a combination of the accepted answer, some other items I found, and a bit of my own work, here's the simplest way I've found to accomplish this menial task. In short:
Enum
public enum EnumOptions
{
[Display(Description = "Option 1")]
OptionOne= 1,
[Display(Description = "Option 2")]
OptionTwo,
[Display(Description = "Option 3")]
OptionThree
}
Converter
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 (partial)
public IReadOnlyList<EnumOptions> Options { get; }
private EnumOptions _selectedOption;
public EnumOptions SelectedOption
{
get { return _selectedOption; }
set
{
_selectedOption = value;
OnPropertyChanged(() => SelectedOption);
}
}
// Initialization in constructor
Options = EnumExtensions.GetValues<EnumOptions>().ToArray();
// If you want to set a default.
SelectedOption = Options[0];
Extensions
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;
}
/// <summary>
/// Enumerates all enum values
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <returns>IEnumerable containing all enum values</returns>
/// <see cref="http://stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values"/>
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof (T)).Cast<T>();
}
}
XAML (partial)
<TextBlock Grid.Row="1">Choose an option</TextBlock>
<ComboBox Grid.Row="2"
ItemsSource="{Binding Options}"
SelectedItem="{Binding SelectedOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumToDisplayConverter}}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Supplement to the above examples to show decorating the enum with attributes.
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
}
BTW, I wonder why you needed to convert back the description to enum. If you provide the enums itself as ItemSource, you can use the description technique to show the display value in the ComboBox, however, once an item is selected you can directly have an enum as selected item.
Here is ConvertBack method:
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
Full Converter Code:
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();
}
}
EDIT
Here is my ComboBox XAML:
<ComboBox ItemsSource="{Binding SampleValues}"
SelectedItem="{Binding SelectedValue, Converter={StaticResource enumConverter}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource enumConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
[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;
}
}
The extension method in the example might look like this:
public static string Description(this MyEnum enumVal)
{
// you could use a switch statement here;
// or maybe a Dictionary
}
Here is my working well example:
Enum definition:
public enum MyEnum
{
[Description("Exchange 2007")]
E2007,
[Description("Exchange 2010")]
E2010,
[Description("Exchange 2013")]
E2013,
};
Helper class:
public static class cHelperClass
{
#region GetValuesAndDescriptions
public static object[] GetValuesAndDescriptions(Type enumType)
{
var kvPairList = new List<KeyValuePair<string, string>>();
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<string, string>(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<StringValueAttribute>()
.Select(a => a.Value)
.FirstOrDefault() ?? enumItem.ToString();
}
public static string GetName(Type enumType, object value)
{
return Enum.GetName(enumType, value);
}
#endregion
}
XAML:
<UserControl.Resources>
<!-- ObjectDataProvider für WindowStyles -->
<ObjectDataProvider x:Key="myEnumResource" MethodName="GetValuesAndDescriptions" ObjectType="classes:cHelperClass">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="classes:MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource myEnumResource}}" DisplayMemberPath="Description" SelectedValuePath="Value" SelectedValue="{Binding MyEnum, Mode=TwoWay}" />