pr0g33k

Displaying an enum in an MVC DropDown with custom text using the DisplayAttribute

I'm working on a project that has several classes with enum-backed properties. When rendering those properties in an MVC view, I wanted to display them as a dropdown list. Here's an extension method I created that does that:

public static IHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    Type enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
    IEnumerable<Object> enumValues = Enum.GetValues(enumType).Cast<Object>();
    IEnumerable<SelectListItem> items = from enumValue in enumValues
                                        select new SelectListItem
                                        {
                                            Text = enumValue.ToString(),
                                            Value = ((Int32)enumValue).ToString(),
                                            Selected = enumValue.Equals(metadata.Model)
                                        };
    return html.DropDownListFor(expression, items, String.Empty, null);
}
    

This extension takes the enum and displays each enumerator exactly as it's written. That seemed to work pretty well for the simple enums I had in my project. Then I created and enum that looked like this:

public enum DeliveryMethod
{
    CompetitiveSealedProposal,
    ConstructionManagerRisk,
    ConstructionManagerAgent
}
    

That gave me a pretty ugly dropdown list and didn't match up with the customer's definitions for those items and what they wanted to see in the UI. Then it hit me: I can use the DisplayAttribute and give each enumeration a "Name."

public enum DeliveryMethod
{
    [Display(Name = "Competitive Sealed Proposal")]
    CompetitiveSealedProposal,
    [Display(Name = "Construction Manager @ Risk")]
    ConstructionManagerRisk,
    [Display(Name = "Construction Manager - Agent")]
    ConstructionManagerAgent
}
    

Next, I added a function to extract the value from the DisplayAttribute:

private static String GetText(Object e)
{
    FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
    DisplayAttribute[] displayAttributes = fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];
    return null != displayAttributes && displayAttributes.Length > 0 ? displayAttributes[0].Name : e.ToString();
}
    

Then I updated the extension to take advantage of the new function:

public static IHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    Type enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
    IEnumerable<Object> enumValues = Enum.GetValues(enumType).Cast<Object>();
    IEnumerable<SelectListItem> items = from enumValue in enumValues
                                        select new SelectListItem
                                        {
                                            Text = GetText(enumValue),
                                            Value = ((Int32)enumValue).ToString(),
                                            Selected = enumValue.Equals(metadata.Model)
                                        };
    return html.DropDownListFor(expression, items, String.Empty, null);
}
    

Voila! Using the extension is as simple as this:

@Html.DropDownListFor(m => m.DeliveryMethod)
    

The extension also takes care of the selected value.

Posted on 6/7/2013 at 05:06 PM
Tags: MVCC#

Comments:

Leave a comment
  1. CAPTCHA