HtmlHelper DropDownList for Enumerations

I’ve really been enjoying the html helpers baked into the ASP.Net MVC framework. To compliment the SelectList extensions that I use, I often use this extension as well.  It displays a drop down of enum values for the specified property.  It will attempt to get the name via the DisplayAttribute.  If the attribute is not present, then it will just get the name from the enum value.

I created an extension method to get the Name of an enum value (as described above):

private static readonly Dictionary<Enum, string> NameCache = new Dictionary<Enum, string>();
public static string GetName(this Enum type)
{
  if (NameCache.ContainsKey(type))
    return NameCache[type];

  var enumType = type.GetType();
  var info = enumType.GetField(type.ToString());
  if (info == null)
    return string.Empty;

  var displayAttribute = info.GetCustomAttributes(false).OfType<DisplayAttribute>().FirstOrDefault();
  var value = string.Empty;
  if (displayAttribute != null)
    value = displayAttribute.GetName() ?? string.Empty;

  NameCache.Add(type, value);

  return value;
}

I then make use of that extension with the enum dropdown helper:

public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
  return htmlHelper.DropDownListForEnum(expression, null, null);
}
public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
  return htmlHelper.DropDownListForEnum(expression, new RouteValueDictionary(htmlAttributes));
}
public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
  return htmlHelper.DropDownListForEnum(expression, null, htmlAttributes);
}
public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string optionLabel)
{
  return htmlHelper.DropDownListForEnum(expression, optionLabel, null);
}
public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string optionLabel, object htmlAttributes)
{
  return htmlHelper.DropDownListForEnum(expression, optionLabel, null);
}
public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string optionLabel, IDictionary<string, object> htmlAttributes)
{
  if (expression == null)
    throw new ArgumentNullException("expression");

  var member = expression.Body as MemberExpression;
  if (member == null)
    throw new ArgumentNullException("expression");

  var selectedValue = string.Empty;
  var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
  if (metadata.Model != null)
  {
    selectedValue = metadata.Model.ToString();
  }
  var enumType = Nullable.GetUnderlyingType(member.Type) ?? member.Type;

  var listItems = new List<SelectListItem>();
  foreach (var name in Enum.GetNames(enumType))
  {
    var type = Enum.Parse(enumType, name) as Enum;
    listItems.Add(new SelectListItem
    {
      Text = type.GetName(),
      Value = name,
      Selected = name == selectedValue
    });
  }

  return htmlHelper.DropDownListFor(expression, listItems, optionLabel, htmlAttributes);
}

The beauty of this extension method is that it uses the DropDownListFor(…) helper baked into the framework already. So validation, etc is wired up for me. Also worth noting, this extension works with nullable and non-nullable properties. Hope this helps someone save some time…

3 thoughts on “HtmlHelper DropDownList for Enumerations

  1. Hi,

    that looks fine to me, but i’ve got stuck using it. In which namespace do you pack these helpers so that you can use it in a razor template? Could you please add an example using it.

    In my case the intellisense shows me the full method, including the “this Htmlhelper” etc. That looks wrong 🙂

    1. Say your enum and view model object look something like:

      public enum MyEnumType {
      [Display(Name = "Something cool")
      SomethingCool = 0,
      [Display(Name = "Something else")
      SomethingElse = 1
      }

      public class MyModel {
      public MyEnumType Type { get; set; }
      }

      Example usage would be:

      @Html.DropDownListForEnum(x => x.Type)

  2. Thank you for this, really saved me quite some time. One small addition I made was in the GetName method where the DisplayName attribute value is initialised:

    var value = string.Empty;

    I changed to:

    var value = info.Name;

    So that the [Display(Name=…)] annotation is not mandatory and simply takes the enum value when not present. In my case, I can simply do this:

    public enum Location
    {
    [Display(Name = “Not Yet Known”)]
    Tbc,
    Home,
    Away
    } ;

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.