Asp.net 4.5 mvc or webforms – model binding dropdownlist to an enum with description attributes

One of the more common problems people encounter when working with any .Net user application is the need to put a UI on top of some enumeration. Normally you need to present a friendly list of all the possible items in the enumerator list, then allow the user to pick one of them. This UI typically takes the form of a drop down list, combo box, list box, or similar.

Enums are wonderful in C#, but unlike some other languages, they are also a very thin type. Enums define a collection of named constants. By default, each enumerator in the list equates to an underlying integer value.

Here is an example Enum, and for clarity I’ve specified the value for each enumerator:

public enum CarMake
{
    Ford,     //0
    Chevy,    //1
    Toaster   //2
}

Enums are lightweight, highly efficient, and often very convenient –until you start trying to map them to a UI anyway.

Each of the items, enumerators, within the enum have a name, but the name cannot contain white space, special characters, or punctuation. For this reason, they are rarely user-friendly when converted to a string and slapped into your dropdown lists.

Enter the DescriptionAttribute (from the System.ComponentModel namespace). This attribute allows you to tag your enumerators with a nice descriptive text label, which will fit the UI pretty well if only you can dig the value up. Unfortunately, reading attributes is a cumbersome job involving reflection.

Here is the same enum decorated with descriptions:

public enum CarMake
{
	[Description("Ford Motor Company")]
	Ford,     //0

	[Description("Chevrolet")]
	Chevy,    //1

	[Description("Kia")]
	Toaster   //2
}

To bind up an enum to a drop down list, many developers tend to just manually hard-code the list with user-friendly text values and corresponding integer values, then map the selected integer to right enumerator on the back-end. This works fine until someone comes along later and changes the enum, after which your UI is horribly busted.

To get around this mess, I’ve put together a set of extensions that solves this problem for the common enum to drop down list cases.

Note: I’m using the SelectList class, which comes from Asp.net MVC, as an intermediary container. I then bind the SelectList to the appropriate UI control. You can use SelectList in Asp.net webforms, and most other UI frameworks as well, but you’ll need to implement the code for SelectList. The easiest way to do this is to include the source files for SelectList into your own projects.

The code for SelectList can be found on the AspNetWebStack project page over at CodePlex. Here are the three files needed for SelectList :

The first step in solving the problem is to have an extension method that takes care of reading the description from the enumerators in your enum.

public static string GetDescription(this Enum enumeration)
{
	Type type = enumeration.GetType();
	MemberInfo[] memberInfo = type.GetMember(enumeration.ToString());

	if (memberInfo != null && memberInfo.Length > 0)
	{
		var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

		if (attributes.Length > 0)
		{
			return ((DescriptionAttribute)attributes.First()).Description;
		}
	}
	return enumeration.ToString(); ;
}

To get an enumerator’s description using this extension method:

string text = CarMake.Ford.GetDescription();

The next challenge is to build a select list for the enum.

public static SelectList ToSelectList(this Enum enumeration, object selectedValue = null, bool includeDefaultItem = true)
{
	var list = (from Enum e in Enum.GetValues(enumeration.GetType())
				select new SelectListQueryItem<object> { 
				   ID = Enum.Parse(enumeration.GetType(), Enum.GetName(enumeration.GetType(), e)), 
				   Name = e.GetDescription() }).ToList();

	if (includeDefaultItem)
	{
		list.Insert(0, new SelectListQueryItem<object> { ID = null, Name = "-- select --"});
	}
	return new SelectList(list, "ID", "Name", selectedValue);
}
internal class SelectListQueryItem<T>
{
    public string Name { get; set; }
    public T ID { get; set; }
}

To get the select list using this extension, you just new-up the enum and call the method:

var carSelectList = new CarMake().ToSelectList();

This extension has an optional parameter to set which item in the list should be selected, and another optional parameter that will include a default item in the SelectList (you may want to adjust this extension to match your own convention for default items).

Here is an example that sets a selected value and includes a default item:

var carSelectList = new CarMake().ToSelectList(CarMake.Ford, true)

I’ve been working in C# for over ten years, and until just this week I had no idea that you could instantiate an enum with the new keyword. Of course I cannot think of reason why you’d normally want to new-up an enum either, but the capability is handy for this extension.

You can also use this extension by calling it on one of the specific enumerator items too. This example does exactly the same as the previous example:

var carSelectList = CarMake.Ford.ToSelectList(CarMake.Ford, true);

I personally prefer the new-up pattern in this case, since it isn’t intuitive that calling ToSelectList on a specifc item would return the list of ALL items from the containing enum.

Now that we have the SelectList, all we have to do is bind it up to a DropDownList.

In Asp.net WebForms 4.5, using model binding, this looks like this:

<asp:DropDownList ID="CarMakeDropDown" runat="server" 
	SelectMethod="GetCarMakeDropDownItems"
	ItemType="MyApp.SomeNameSpace.SelectListItem" 
	DataTextField="Text" 
	DataValueField="Value"
	SelectedValue="<%# BindItem.CarMakeValue %>" 
/>
protected SelectList GetCarMakeDropDownItems()
{   
	return new CarMake().ToSelectList();
}

For more in-depth examples of various techniques for binding SelectList to DropDownList in webforms, see my previous article titled “Asp.net 4.5 webforms – model binding selected value for dropdownlist and listbox“.

In Asp.net MVC model binding to a SelectList is a very common and routine pattern, so I’m not going to provide a detailed example here. Generally though, you make sure your model includes a property or method for getting the enum’s SelectList, then you use the Html.DropDownList or Html.DropDownListFor helper methods. This would look something like this:

@Html.DropDownListFor(model => model.CarMakeValue, Model.CarMakesSelectList)

 

 

2 Replies to “Asp.net 4.5 mvc or webforms – model binding dropdownlist to an enum with description attributes”

    1. Sorry about that, apparently I left that bit out of the examples (I’ve fixed that). It is a simple class:

      internal class SelectListQueryItem<T>
      {
      public string Name { get; set; }
      public T ID { get; set; }
      }

Leave a Reply to Pedro Cancel reply

Your email address will not be published. Required fields are marked *