Binding Enum-Values to a ComboBox - CodeProject

:

Introduction

The solution presented here provides a simple and tidy way to bind Enums to a ComboBox or (with only minor adjustments) to any other bindable control. If you decorated your Enum-members with a DescriptionAttribute, that description can be used as the DisplayMember for the Control-Binding, otherwise the name of the Enum-member can be used instead.

Background

The idea for this tip/trick originates from my answer to a recent question in CodeProject Q&A where in a comment it was suggested that I write it up as a tip/trick. The inquirer of the Q&A-question had troubles implementing a solution proposed to a question on Code Review (StackExchange) which is where the original code comes from (especially StackExchange-Member Jesse C. Slicer). I only claim credit for making it a generic solution (along with some other minor improvements) and packing it up into a tidy sample.

Using the Code

The sample uses these two Enum-definitions - one with, one without Description-Attributes:

public enum AnimalOption
{
    [Description("flying animal")]
    Bird,
    [Description("best friend")]
    Dog,
    [Description("cuddly carnivore")]
    Cat
}

public enum ShapeOption
{
    Circle,
    Rectangle,
    Line
}

They get bound to ComboBoxes in the constructor of the Form. As you can see, it's done via a generic extension method to ComboBox that takes the Enum-Type as generic type argument and a DisplayMode-argument that tells whether it should look for Description-Attributes to use for the DisplayMember or use the name of the Enum-Member instead (ValueToString).

public Form1()
{
    InitializeComponent();

    AnimalComboBox.BindEnum<AnimalOption>(DisplayMode.DescriptionAttribute);
    ShapeComboBox.BindEnum<ShapeOption>(DisplayMode.ValueToString);
}

The implementation of the extension method and its "helpers" is as follows:

public class EnumBindingItem<TEnum>
{
    public string Description { get; private set; }
    public TEnum Value { get; set; } // setter needs to be public for the binding to work

    public EnumBindingItem(string description, TEnum value)
    {
        Description = description;
        Value = value;
    }
}

public enum DisplayMode
{
    DescriptionAttribute,
    ValueToString
}

public static class EnumBindingExtension
{
    public static void BindEnum<TEnum>(this ComboBox cbo, DisplayMode mode)
    {
        cbo.DataSource = Enum.GetValues(typeof(TEnum))
                                .Cast<TEnum>()
                                .Select(value => CreateEnumBindingItem(value, mode))
                                .OrderBy(item => item.Value)
                                .ToList();

        cbo.DisplayMember = "Description";
        cbo.ValueMember = "Value";
    }

    private static EnumBindingItem<TEnum> CreateEnumBindingItem<TEnum>(TEnum value, DisplayMode mode)
    {
        string description;

        if (mode == DisplayMode.DescriptionAttribute)
        {
            FieldInfo enumMember = typeof(TEnum).GetField(value.ToString());
            DescriptionAttribute attribute = (DescriptionAttribute)
                Attribute.GetCustomAttribute(enumMember, typeof(DescriptionAttribute));
            description = attribute.Description;
        }
        else
        {
            description = value.ToString();
        }

        return new EnumBindingItem<TEnum>(description, value);
    }
}

In the SelectedValueChanged-EventHandlers of the ComboBoxes, you can then easily get the selected Enum-value like this:

private void AnimalComboBoxSelectedValueChanged(object sender, EventArgs e)
{
    AnimalOption selectedAnimal = ((EnumBindingItem<AnimalOption>)AnimalComboBox.SelectedItem).Value;

    AnimalSelectionLabel.Text = selectedAnimal.ToString();
}

private void ShapeComboBoxSelectedValueChanged(object sender, EventArgs e)
{
    ShapeOption selectedShape = ((EnumBindingItem<ShapeOption>)ShapeComboBox.SelectedItem).Value;

    ShapeSelectionLabel.Text = selectedShape.ToString();
}

I hope it's useful to you! Comments are welcome!

History

  • v1.1 - March 16, 2015
    • Incorporated the suggestion from Klaus Luedenscheidt and one of Sergey Alexandrovich Kryukov's suggestions. No functional changes.
  • v1.0 - March 15, 2015