Click here to Skip to main content
15,889,281 members
Articles / Desktop Programming
Tip/Trick

Binding Enum-Values to a ComboBox

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
15 Mar 2015CPOL1 min read 17.6K   115   12   7
Tidy, generic solution to bind Enums (with or without a DescriptionAttribute) to a ComboBox or other Controls

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:

C#
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).

C#
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:

C#
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:

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
SuggestionDisplayName vs Description Pin
Daniele Rota Nodari16-Mar-15 5:08
Daniele Rota Nodari16-Mar-15 5:08 
GeneralRe: DisplayName vs Description Pin
manchanx16-Mar-15 5:29
professionalmanchanx16-Mar-15 5:29 
GeneralMy vote of 4 Pin
Klaus Luedenscheidt15-Mar-15 20:05
Klaus Luedenscheidt15-Mar-15 20:05 
GeneralRe: My vote of 4 Pin
manchanx16-Mar-15 1:12
professionalmanchanx16-Mar-15 1:12 
GeneralRe: My vote of 4 Pin
Klaus Luedenscheidt16-Mar-15 1:57
Klaus Luedenscheidt16-Mar-15 1:57 
GeneralMy vote of 4 Pin
Sergey Alexandrovich Kryukov15-Mar-15 13:50
mvaSergey Alexandrovich Kryukov15-Mar-15 13:50 
Short elegant solution, but I would not encourage violation of very reasonable Microsoft naming conventions, so I voted 4.

This naming problem is the use of '_' which is the sign of using the event handler generated by the designer. Many members even fail to mention += operator assuming that the event handled should be apparent from the handler name, which is of course wrong (you mentioned the event name, which is much better). Some even lose the += operator by some reason, keep using the handler and ask questions why it doesn't invoke.

Moreover, I never ever use any designer-generated event handlers and often advise others not to do it, which can be considered as controversial issue (but my arguments against using such handlers are pretty strong). But, more general, overuse of the designer is a real bad problem.

One funny thing is that it's pretty hard to explain how designer-generated names can violate Microsoft naming conventions. But they do. The code generator simply has no choice, because "it does not know the programmers intentions". Come to think about, such naming violation is even good, because on can immediately see what names were auto-generated and which were re-touched because they were renamed (why do we have refactoring engine, after all?). Yes, all auto-generated names are not meant to be kept, they need to be renamed even if the designer generated the code. The names like "label1", "label2" should never be tolerated, as they present really nasty maintenance problem.

Now, your work can further be improved. How about, for example, the localization? human-readable names?

For some ideas, please see my articles of enumeration cycle, in particular,
Enumeration Types do not Enumerate! Working around .NET and Language Limitations[^],
Human-readable Enumeration Meta-data[^],
Bitwise Enumeration Editor for PropertyGrid and Visual Studio[^].

—SA


modified 15-Mar-15 20:23pm.

GeneralRe: My vote of 4 Pin
manchanx15-Mar-15 14:12
professionalmanchanx15-Mar-15 14:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.