Databinding an enum property to a ComboBox in WPF
You can create a custom markup extension.
Example of usage:
enum Status{ [Description("Available.")] Available, [Description("Not here right now.")] Away, [Description("I don't have time right now.")] Busy}
At the top of your XAML:
xmlns:my="clr-namespace:namespace_to_enumeration_extension_class
and then...
<ComboBox ItemsSource="{Binding Source={my:Enumeration {x:Type my:Status}}}" DisplayMemberPath="Description" SelectedValue="{Binding CurrentStatus}" SelectedValuePath="Value" />
And the implementation...
public class EnumerationExtension : MarkupExtension { private Type _enumType; public EnumerationExtension(Type enumType) { if (enumType == null) throw new ArgumentNullException("enumType"); EnumType = enumType; } public Type EnumType { get { return _enumType; } private set { if (_enumType == value) return; var enumType = Nullable.GetUnderlyingType(value) ?? value; if (enumType.IsEnum == false) throw new ArgumentException("Type must be an Enum."); _enumType = value; } } public override object ProvideValue(IServiceProvider serviceProvider) { var enumValues = Enum.GetValues(EnumType); return ( from object enumValue in enumValues select new EnumerationMember{ Value = enumValue, Description = GetDescription(enumValue) }).ToArray(); } private string GetDescription(object enumValue) { var descriptionAttribute = EnumType .GetField(enumValue.ToString()) .GetCustomAttributes(typeof (DescriptionAttribute), false) .FirstOrDefault() as DescriptionAttribute; return descriptionAttribute != null ? descriptionAttribute.Description : enumValue.ToString(); } public class EnumerationMember { public string Description { get; set; } public object Value { get; set; } } }
In the viewmodel you can have:
public MyEnumType SelectedMyEnumType { get { return _selectedMyEnumType; } set { _selectedMyEnumType = value; OnPropertyChanged("SelectedMyEnumType"); }}public IEnumerable<MyEnumType> MyEnumTypeValues{ get { return Enum.GetValues(typeof(MyEnumType)) .Cast<MyEnumType>(); }}
In XAML the ItemSource
binds to MyEnumTypeValues
and SelectedItem
binds to SelectedMyEnumType
.
<ComboBox SelectedItem="{Binding SelectedMyEnumType}" ItemsSource="{Binding MyEnumTypeValues}"></ComboBox>
I prefer not to use the name of enum in UI. I prefer use different value for user (DisplayMemberPath
) and different for value (enum in this case) (SelectedValuePath
). Those two values can be packed to KeyValuePair
and stored in dictionary.
XAML
<ComboBox Name="fooBarComboBox" ItemsSource="{Binding Path=ExampleEnumsWithCaptions}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding Path=ExampleProperty, Mode=TwoWay}" >
C#
public Dictionary<ExampleEnum, string> ExampleEnumsWithCaptions { get; } = new Dictionary<ExampleEnum, string>() { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, };private ExampleEnum example;public ExampleEnum ExampleProperty{ get { return example; } set { /* set and notify */; }}
EDIT: Compatible with the MVVM pattern.