WPF binding ComboBox to enum (with a twist) WPF binding ComboBox to enum (with a twist) wpf wpf

WPF binding ComboBox to enum (with a twist)


I would suggest a DataTemplate and a ValueConverter. That will let you customize the way it's displayed, but you would still be able to read the combobox's SelectedItem property and get the actual enum value.

ValueConverters require a lot of boilerplate code, but there's nothing too complicated here. First you create the ValueConverter class:

public class ModeConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter,        CultureInfo culture)    {        return ((Mode) value).GetDescription();    }    public object ConvertBack(object value, Type targetType, object parameter,        CultureInfo culture)    {        throw new NotSupportedException();    }}

Since you're only converting enum values to strings (for display), you don't need ConvertBack -- that's just for two-way binding scenarios.

Then you put an instance of the ValueConverter into your resources, with something like this:

<Window ... xmlns:WpfApplication1="clr-namespace:WpfApplication1">    <Window.Resources>        <WpfApplication1:ModeConverter x:Key="modeConverter"/>    </Window.Resources>    ....</Window>

Then you're ready to give the ComboBox a DisplayTemplate that formats its items using the ModeConverter:

<ComboBox Name="comboBox" ...>    <ComboBox.ItemTemplate>        <DataTemplate>            <TextBlock Text="{Binding Converter={StaticResource modeConverter}}"/>        </DataTemplate>    </ComboBox.ItemTemplate></ComboBox>

To test this, I threw in a Label too, that would show me the actual SelectedItem value, and it did indeed show that SelectedItem is the enum instead of the display text, which is what I would want:

<Label Content="{Binding ElementName=comboBox, Path=SelectedItem}"/>


This is how I am doing it with MVVM. On my model I would have defined my enum:

    public enum VelocityUnitOfMeasure    {        [Description("Miles per Hour")]        MilesPerHour,        [Description("Kilometers per Hour")]        KilometersPerHour    }

On my ViewModel I expose a property that provides possible selections as string as well as a property to get/set the model's value. This is useful if we don't want to use every enum value in the type:

    //UI Helper    public IEnumerable<string> VelocityUnitOfMeasureSelections    {        get        {            var units = new []                            {                               VelocityUnitOfMeasure.MilesPerHour.Description(),                               VelocityUnitOfMeasure.KilometersPerHour.Description()                            };            return units;        }    }    //VM property    public VelocityUnitOfMeasure UnitOfMeasure    {        get { return model.UnitOfMeasure; }        set { model.UnitOfMeasure = value; }    }

Furthermore, I use a generic EnumDescriptionCoverter:

public class EnumDescriptionConverter : IValueConverter{    //From Binding Source    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)    {        if (!(value is Enum)) throw new ArgumentException("Value is not an Enum");        return (value as Enum).Description();    }    //From Binding Target    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)    {        if (!(value is string)) throw new ArgumentException("Value is not a string");        foreach(var item in Enum.GetValues(targetType))        {            var asString = (item as Enum).Description();            if (asString == (string) value)            {                return item;            }        }        throw new ArgumentException("Unable to match string to Enum description");    }}

And finally, with the view I can do the following:

<Window.Resources>    <ValueConverters:EnumDescriptionConverter x:Key="enumDescriptionConverter" /></Window.Resources>...<ComboBox SelectedItem="{Binding UnitOfMeasure, Converter={StaticResource enumDescriptionConverter}}"          ItemsSource="{Binding VelocityUnitOfMeasureSelections, Mode=OneWay}" />


I like the way you think. But GetCustomAttributes uses reflection. What is that going to do to your performance?

Check out this post:WPF - Displaying enums in ComboBox controlhttp://www.infosysblogs.com/microsoft/2008/09/wpf_displaying_enums_in_combob.html