Databinding an enum property to a ComboBox in WPF Databinding an enum property to a ComboBox in WPF wpf wpf

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.