Introduction

Over course of my professional life as the GUI programmer, countless times I needed to populate combo box with values mapped to some Enum values defined in the program. Then after user selection, I needed to translate selected item back to the corresponding Enum value. I always ended up with ugly and difficult to maintain code, where Enum values were manually mapped to the ComboBox instance using ComboBox selected item index or string value.

I knew it could be done better but lack of time, laziness, 'I'll fix it later' approach prevented me from coding proper solution. But enough is enough.

Extension methods introduced with C# 3.0 provide a very convenient way to extend existing types with additional methods. It's simple and elegant and what is most important is that it is very easy to integrate with targeted types. Only thing you have to do is add the reference to the class containing extensions and add using directive to the extension namespace in the code.

Code Explained

To cover the needed functionality, the following three methods are sufficient:

  1. Method to bind any Enum type with ComboBox instance. After binding, ComboBox instance should behave as GUI representation of the underlying Enum type. In another words, ComboBox items should be tightly related to Enum fields.

    public static void BindWithEnum<T>(this ComboBox comboBox, T selectedValue) 

    selectedValue parameter determines initially selected ComboBox item.

  2. Method to retrieve currently selected ComboBox item.

    public static T GetSelectedValue<T>(this ComboBox comboBox)  
  3. And finally, method to change ComboBox selection.

    public static void SetSelectedValue<T>(this ComboBox comboBox,T selectedValue) 

    selectedValue parameter determines new selected ComboBox item.

BindWithEnum Method

This method uses reflection to enumerate all fields of given Enum type. For each field, it retrieves Description attribute in order to provide human friendly text in the ComboBox item. Next, the method adds Description text and associated with it Enum value to the ComboBox item list. ComboBox becomes tightly coupled visual representation of underlying Enum.

public static void BindWithEnum<T>(this ComboBox comboBox, T selectedValue)
{
    Type enumType = typeof(T);
 
    if (!enumType.IsEnum)
       throw new Exception("Only Enum types are allowed.");
 
    //List containing ComboBox items.
    List<KeyValuePair<string, 
    T>> comboBoxItems = new List<KeyValuePair<string, T>>();
    //Temporary store for item that needs to be selected.
    KeyValuePair<string, T>? selectedItem = null;
 
    //Loop through all Enum values and build the list of ComboBox items.
    foreach (T enumValue in Enum.GetValues(enumType))
    {
       string name = Enum.GetName(enumType, enumValue);
       FieldInfo fi = enumType.GetField(name);
 
       string descriptiveName = fi.GetDescriptionAttributeOrName();
 
       KeyValuePair<string,T> item = 
       	new KeyValuePair<string,T>(descriptiveName,enumValue);
       comboBoxItems.Add(item);
 
       //If current loop enumValue is equal to the value that needs to be initially 
       //selected, store it in temporary location.
       if (enumValue.Equals(selectedValue))
          selectedItem = item;
    }
 
    //Set ComboBox values
    comboBox.DisplayMember = "Key";
    comboBox.ValueMember = "Value";
    comboBox.DataSource = comboBoxItems;
 
    //Set initial selection of the ComboBox
    if (selectedItem != null)
       comboBox.SelectedItem = selectedItem.Value;
} 
Example

The following code binds Enum type OptionsToSelectFrom with comboBox1 and makes OptionsToSelectForm.Opt3 selected item in the comboBox1.

 comboBox1.BindWithEnum<OptionsToSelectFrom>(OptionsToSelectFrom.opt3); 

GetSelectedValue Method

Method retrieves Enum value associated with currently selected ComboBox item.

public static T GetSelectedValue<T>(this ComboBox comboBox)
{
   KeyValuePair<string, T> 
   selectedItem = (KeyValuePair<string, T>)comboBox.SelectedItem;
 
   return (T)Convert.ChangeType(selectedItem.Value, typeof(T));
}
Example
OptionsToSelectFrom selectedValue = 
	comboBox1.GetSelectedValue<OptionsToSelectFrom>();

SetSelectedValue Method

This method is used to set selected ComboBox item to provided Enum value.

public static void SetSelectedValue<T>(this ComboBox comboBox,T selectedVaue)
{
   string name = Enum.GetName(typeof(T), selectedOption);
   FieldInfo fi = typeof(T).GetField(name);
   string descriptiveName = fi.GetDescriptionAttributeOrName();
 
   KeyValuePair<string, T> selectedItem = 
                 new KeyValuePair<string, T>(descriptiveName, selectedOption);
   comboBox.SelectedItem = selectedItem;
}  

Example

 comboBox1.SetSelectedValue<OptionsToSelectFrom>(OptionsToSelectFrom.opt2);

Some Extras

As the "side effect" of coding ComboBoxExtensions I got a small set of Type related extensions. Initially, I defined them as private helper methods used internally for ComboboxExtensions but after giving it some thought, I came to the conclusion that they can have some value by themselves, so I decided to expose them as public extension methods as well.

Below, you can find their names and usage examples.

TryGetDefaultValueAttribute Method

This method simplifies retrieval of DefaultValue attribute for the given type. If DefaultValue exists for given type, its value is returned int out parameter and method return value is true. If DefaultValue attribute does not exist for the given type, the method returns false and value of output parameter is indeterminate.

public static bool TryGetDefaultValueAttribute<T>(this Type type, out T defaultValue)
{
    DefaultValueAttribute[] defaultValueAttribute = 
    (DefaultValueAttribute[])type.GetCustomAttributes(typeof(DefaultValueAttribute),false);

    if (defaultValueAttribute.Length > 0)
    {
        defaultValue = (T)Convert.ChangeType(defaultValueAttribute[0].Value, typeof(T));
        return true;
    }
    else
    {
        defaultValue = Activator.CreateInstance<T>();
        return false;
    }
}    
Example
if (!typeof(OptionsToSelectFrom).
      TryGetDefaultValueAttribute<OptionsToSelectFrom>(out defValue))
{
   MessageBox.Show("Type does not have DefaultValue attribute");
} 

GetDefaultValueAttribute

This method retrieves DefaultValue attribute in a similar way as TryGetDefaultValueAttribute. If attribute does not exist, the method raises an exception.

public static T GetDefaultValueAttribute<T>(this Type type)
{
   T retValue;
   if (type.TryGetDefaultValueAttribute<T>(out retValue))
      return retValue;
   else
      throw new Exception"No DefaultValue associated with the type.", type.ToString()));
}

GetDescriptionAttributeOrName

This method retrieves value of Description attribute for given enum value. If Description attribute does not exist, the method returns field name.

public static string GetDescriptionAttributeOrName(this Enum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    FieldInfo fi = type.GetField(name);
    return fi.GetDescriptionAttributeOrName();
}

Using the Code

It is very simple.

  1. In your project, add reference to ComboBoxExttensions.dll

  2. Add the following using directive to your code: using Proxoft.WinForms;

  3. And you are ready to go. The below snippet shows an example of how to bind Enum with ComboBox and how to set and retrieve current selection. You can also download the source code and demo program and get yourself familiar with extensions functionality.

The following code snippets show most of the use cases:

//This is the namespace where extension is defined
using Proxoft.WinForms;
 
(..)
 
//Structure that will bind with ComboBox

    [DefaultValue(OptionsToSelectFrom.opt3)]
    public enum OptionsToSelectFrom
    {
        [Description("Option One")]
        opt1,
        [Description("Option Two")]
        opt2,
        [Description("Option Three")]
        opt3,
        [Description("Option Four")]
        opt4
    }
 
(...)
 
//The following line binds 'OptionsToSelectFrom' enum with comboBox1.
//Initially selected comboBox value will be set to 'OptionsToSelectFrom.opt3'.  

 comboBox1.BindWithEnum<OptionsToSelectFrom>(OptionsToSelectFrom.opt3); 
 
(...)
 
//The following line of code changes selection to 'OptionsToSelectFrom.opt2'.
 
 comboBox1.SetSelectedValue<OptionsToSelectFrom>(OptionsToSelectFrom.opt2);  

(...)
 
//The following line shows how to examine currently selected value
 
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    label1.Text =  comboBox1.GetSelectedValue<OptionsToSelectFrom>().ToString();
}  

Home  bullet Products  bullet Downloads  bullet About Us  bullet Contact Us

Credit Card Logo