C# and .NET,  Geeks,  Programming

Showing Enums in a dropdownlist on our ASP.NET MVC view

A little while ago I posted a discussion on a method to decorate Enums with attributes to provide some flexibility with how they are displayed.

Background

This came about in a project I worked on where we wanted to show user friendly names of an enumeration on a Web UI page, but the same Enum was to be serialized to XML using a different set of names. Most articles concentrated on decorating an Enum with one attribute. We needed two, and wanted the ability to set which of those two took precedence in different scenarios.

The code

Here, I’m showing an implementation on how you could use that functionality to provide an easy solution to turn Enums into a dropdownlist from your .NET view. This class exposes a-lot of overloads but you will see in main overload that is doing all the work it does the call to our EnumHelper class talked about in my Getting friendly names from an Enum when decorated with multiple attributes post.

Although this might seem like alot of code, it’s really just a bunch of classes all targeted to providing a bit of flexibility when using Enumerations in different output contexts.

First off, I create a extension helper that we can use to build the list:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Serialization;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;

namespace Web.Helpers
{   
    public static partial class SelectExtensionHelper
    {
        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name)
            where TEnum : struct
        {
            return EnumDropDownList(helper, name, null, null, null, null);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name, string selectedValue)
            where TEnum : struct
        {
            return EnumDropDownList(helper, name, selectedValue, null, null, null);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name, string selectedValue, string optionLabel)
            where TEnum : struct
        {
            return EnumDropDownList(helper, name, selectedValue, optionLabel, null, null);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name, string selectedValue, string optionLabel, object htmlAttributes)
            where TEnum : struct
        {
            return EnumDropDownList(helper, name, selectedValue, optionLabel, htmlAttributes, null);
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name, string selectedValue, string optionLabel, object htmlAttributes, string[] excludeList)
            where TEnum : struct
        {
            return EnumDropDownList(helper, name, selectedValue, optionLabel, htmlAttributes, excludeList, typeof(TEnum));
        }

        public static MvcHtmlString EnumDropDownList(this HtmlHelper helper, string name, string selectedValue, string optionLabel, object htmlAttributes, string[] excludeList, Type typeOfEnum)
        {
            List items = EnumHelper.ConvertEnumToSelectListItems(selectedValue, excludeList, typeOfEnum);

            return SelectExtensions.DropDownList(helper, name, items, optionLabel, htmlAttributes);
        }

        public static MvcHtmlString EnumDropDownListFor(this HtmlHelper helper, Expression> expression, string optionLabel, object htmlAttributes, string[] excludeList)
        {
            // Get the property value from the expression
            Func func = expression.Compile();
            TProperty property = func((TModel)helper.ViewContext.ViewData.Model);

            Type propertyType = typeof(TProperty);

            // get underlying type of a nullable type.
            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                propertyType = propertyType.GetGenericArguments()[0];
            }

            // build the list using our EnumHelper class to convert the enum
            List items = EnumHelper.ConvertEnumToSelectListItems(property != null ? property.ToString() : null, excludeList, propertyType);

            var attributes = AttributesHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            if (excludeList != null)
            {
                attributes.Add("data-excluded-option", excludeList.First());
            }

            return SelectExtensions.DropDownListFor(helper, expression, items, optionLabel, attributes);
        }

        public static MvcHtmlString EnumDropDownListFor(this HtmlHelper helper, Expression> expression, string optionLabel, object htmlAttributes)
        {
            return EnumDropDownListFor(helper, expression, optionLabel, htmlAttributes, null);
        }

        public static MvcHtmlString EnumDropDownListFor(this HtmlHelper helper, Expression> expression, string optionLabel)
        {
            return EnumDropDownListFor(helper, expression, optionLabel, null);
        }

        public static MvcHtmlString EnumDropDownListFor(this HtmlHelper helper, Expression> expression)
        {
            return EnumDropDownListFor(helper, expression, null, null);
        }

        ///
        /// Adds MVC3 functionality in that this helper can take html5 data attributes (by converting underscores to hyphens)
        ///
        public static MvcHtmlString CustomDropDownListFor(this HtmlHelper helper, Expression> expression, IEnumerable selectList, string optionLabel, object htmlAttributes)
        {
            var attributes = AttributesHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            return helper.DropDownListFor(expression, selectList, optionLabel, attributes);
        }
    }
}

An extra class helper to allow for html5 data attributes to convert underscores to hyphens:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;

namespace Web.Helpers
{
    public class AttributesHelper
    {
        public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes)
        {
            RouteValueDictionary result = new RouteValueDictionary();
            if (htmlAttributes != null)
            {
                foreach (System.ComponentModel.PropertyDescriptor property in System.ComponentModel.TypeDescriptor.GetProperties(htmlAttributes))
                {
                    result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes));
                }
            }
            return result;
        }
    }
}

And finally an example of using it in your view is as simple as

  <%: Html.EnumDropDownListFor(model => model.MyEnumValue, string.Empty, new { style = "width:135px;" }, new string[] { "Undefined" })%>

Leave a Reply