Tags: , , , , , , , , , | Categories: ASP.Net, C#, MVC, Razor, HTML, HtmlHelper extensions Posted by Scott on 1/6/2012 6:42 PM | Comments (0)

So, we want a way to bind an HTML <select> to an enum, each enum value becoming an <option>. We also want to be able to hide some of the enum values from the <select> so that we can allow existing data to function but stop new data from using these values.

We start by creating an attribute that we can decorate our enum with, marking values as in use or not. If we don't add the attribute the assumption is that all the values of the enum are still in use which saves the effort of updating every enum in the application domain.

public class EnumBindingAttribute : Attribute
{
    public bool IsInUse { get; set; }
}

Then we decorate the enum with the new attribute.

public enum ContactNumberType
{
    [EnumBinding(IsInUse=false)]
    Unknown,
    [EnumBinding(IsInUse = true)]
    Home,
    [EnumBinding(IsInUse = true)]
    Work,
    [EnumBinding(IsInUse = true)]
    Mobile,
    [EnumBinding(IsInUse = false)]
    Fax,
    [EnumBinding(IsInUse = false)]
    Other
}

Now, to bind the enum to the <select> we have an extension to HtmlHelper. This emits a <select> tag with id and name attributes and then enumerates the additional attributes specified in the dictionary, adding each in turn. These additional attributes are essential for aria- and data- which you'll probably be using. Next comes the fun - reflection. We enumerate each of the values in the enum, test for the existence of the EnumBindingAttribute and skip any that have the attribute set to false. For those that we are rendering we check for a DescriptionAttribute and use that if it's present otherwise we render out the enum as a string. If the value of the enum matches the selectedValue parameter we add the selected attribute to the <option> tag.

public static MvcHtmlString DropDownListEnum<T>(this HtmlHelper helper, string name, Type enumeration, string selectedValue, Dictionary<string, object> htmlAttributes)
{
    StringBuilder output = new StringBuilder();
    output.AppendFormat("<select id=\"{0}\" name=\"{0}\"", name);
    foreach (var attribute in htmlAttributes)
    {
        if (attribute.Value != null)
        {
            output.AppendFormat(" {0}=\"{1}\"", attribute.Key, attribute.Value);
        }
        else
        {
            output.AppendFormat(" {0}", attribute.Key);
        }
    }

    output.Append(" >");
    foreach (var enumValue in enumeration.GetEnumValues())
    {
        FieldInfo fieldInfo = enumeration.GetField(enumValue.ToString());
        EnumBindingAttribute[] enumbindingAttributes = (EnumBindingAttribute[])fieldInfo.GetCustomAttributes(typeof(EnumBindingAttribute), false);
        if (!enumbindingAttributes.Any() || enumbindingAttributes.Any(e => e.IsInUse)) // no attribute set implies is in use
        {
            int enumIntValue = (int)enumValue;
            output.Append("<option");
            if (selectedValue == enumIntValue.ToString())
            {
                output.Append(" selected=\"selected\"");
            }

            output.AppendFormat(" value=\"{0}\">", enumIntValue.ToString());
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attributes.Any())
            {
                output.Append(attributes[0].Description);
            }
            else
            {
                output.Append(enumValue.ToString());
            }

            output.Append("</option>");
        }
    }

    output.Append("");
    return MvcHtmlString.Create(output.ToString());
}

Now we just use the HtmlHelper extension!

@model ContactNumber
@using (Html.BeginForm("UpdateContactNumber", "Members", null, FormMethod.Post, null))
{
    @Html.HiddenFor(m => m.Id)
    
Contact Numbers @Html.DropDownListEnum("ContactNumberType", typeof(ContactNumberType), Model == null ? "0" : ((int)Model.ContactNumberType).ToString(), new Dictionary<string, object> { { "aria-required", "true" }, { "aria-labelledby", "ulblType" }, { "required", null } })
}

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading