How to bind an Enum to a DropDownList in ASP.NET MVC

Prior to ASP.NET MVC 5, the only way to bind an enum to a drop down list in an MVC view was to roll out your own HtmlHelper, which is the best way to extend MVC's functionality. These days, with MVC 5 at your disposal, you can bind any enum to a view control easily by calling the "oh so handy" EnumDropDownListFor HTML helper. Details on the helper can be found here and works like any other build in HTML helper, with a model, a model property and a bunch of additional attributes that allow you to decorate your drop down list.

The problem

First, let's see what the problem is with the current (i.e. EnumDropDownListFor) implementation in MVC 5. Using the helper, the values in the drop down box, which is bound to the enum in your model, will look like this:

// Enum in ViewModel
public enum TestEnum
{
    HelloFromOne,
    HelloFromTwo,
    HelloFromThree
}

Drop-down values in HTML:

HelloFromOne
HelloFromTwo
HelloFromThree

Obviously this is neither readable or overly user-friendly.

The solution

The solution to this problem works in two ways:

  • it provides a handy HTML helper if you have to work with MVC 4 or less
  • it improves the default output of MVC 5's HTML Helper

To improve the appearence of the values in the bound drop down, we can decorate the enum values with the Description attribute. The description can contain the readable text that you want to display to your users without compromising the ease that comes from binding directly to an enum. Enough with the talking - show me the code!

The implementation

First we need to update the enum we used in the previous example to include description properies for each enum value:

public enum TestEnum
{
    [Description("First choice")]
    HelloFromOne,
    
    [Description("Second choice")]
    HelloFromTwo,
    
    [Description("Third choice")]
    HelloFromThree
}

The HTML helper code, where all the magic happens, is right below:

public static MvcHtmlString CustomEnumDropDownListFor<TModel, TEnum>(
  this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var values = Enum.GetValues(typeof(TEnum)).Cast<TEnum>();

    var items =
        values.Select(
           value =>
           new SelectListItem
           {
               Text = GetEnumDescription(value),
               Value = value.ToString(),
               Selected = value.Equals(metadata.Model)
           });
           var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
   return htmlHelper.DropDownListFor(expression, items, attributes);
}

public static string GetEnumDescription<TEnum>(TEnum value)
{
    var field = value.GetType().GetField(value.ToString());
    var attributes = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);
    return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}

The first method creates the HTML helper while the second one provides a way to retrieve the Description attribute from the enum. Easy as that.

To use this extension, all you have to do in your MVC view is call it like this:

@Html.CustomEnumDropDownListFor(m => m.TestEnum, new { @class = "dropdownstyle" })

PS - Make sure you follow me on Twitter @christosmatskas for more up-to-date news, articles and tips.