1

I'm currently using this for turning an enum into a radio control,

public static MvcHtmlString RadioButtonForEnum<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression)
{
    var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

    var sb = new StringBuilder();
    var enumType = metaData.ModelType;
    foreach (var field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
    {
        var value = (int)field.GetValue(null);
        var name = Enum.GetName(enumType, value);
        var label = name;
        foreach (DisplayAttribute currAttr in field.GetCustomAttributes(typeof(DisplayAttribute), true))
        {
            label = currAttr.Name;
            break;
        }

        var id = string.Format(
            "{0}_{1}_{2}",
            htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix,
            metaData.PropertyName,
            name
        );
        var radio = htmlHelper.RadioButtonFor(expression, name, new { id = id }).ToHtmlString();
        sb.AppendFormat(
            "<label for=\"{0}\">{1}</label> {2}",
            id,
            HttpUtility.HtmlEncode(label),
            radio
        );
    }
    return MvcHtmlString.Create(sb.ToString());
}

but when trying to adapt it to enum to dropdown:

public static MvcHtmlString DropDownListForEnum<TModel, TProperty>(
   this HtmlHelper<TModel> htmlHelper,
   Expression<Func<TModel, TProperty>> expression)
{
     var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

     var sb = new StringBuilder();
     var enumType = metaData.ModelType;
     sb.Append("<select name=\"" + metaData.PropertyName + "\" id=\"" + metaData.PropertyName + "\" > ");
     foreach (var field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
     {
          var value = (int)field.GetValue(null);
          var name = Enum.GetName(enumType, value);
          var label = name;

          foreach (DisplayAttribute currAttr in field.GetCustomAttributes(typeof(DisplayAttribute), true))
          {
                label = currAttr.Name;
                break;
          }

          var id = string.Format(
                    "{0}_{1}_{2}",
                    htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix,
                    metaData.PropertyName,
                    name
                );
          var listitem = htmlHelper.DropDownListFor(expression, name, new { id = id }).ToHtmlString();
          sb.AppendFormat(
                    "<option value=\"{0}_{1}\">{2}</option> ",
                    id,
                    listitem,
                    HttpUtility.HtmlEncode(label)
                );
     }
     sb.Append("</select>");
     return MvcHtmlString.Create(sb.ToString());
}

I get an error in the var listitem = htmlHelper.DropDownListFor line. Basically I'm not providing the correct information in the method. Could anyone shed any light on this issue?

2
  • The DropDownListFor() method renders the entire drop-down list, complete with all the <select> tags. So you only need to call it once, not inside foreach. Commented Jan 16, 2012 at 8:55
  • Why don't you just follow ASP.NET MVC - Creating a DropDownList helper for enums (Stuart Leeks) blogs.msdn.com/b/stuartleeks/archive/2010/05/21/… Commented Jan 16, 2012 at 22:28

3 Answers 3

5

You can use a static helper that turns enums into select lists.

I've blogged about it here:

http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23

The helper (this will get the value of the description attribute if present):

public static class EnumHelper
{
    public static SelectList SelectListFor<T>(T? selected)
        where T : struct
    {
        return selected == null ? SelectListFor<T>()
                                : SelectListFor(selected.Value);
    }

    public static SelectList SelectListFor<T>() where T : struct
    {
        Type t = typeof (T);
        if (t.IsEnum)
        {
            var values = Enum.GetValues(typeof(T)).Cast<Enum>()
                             .Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });

            return new SelectList(values, "Id", "Name");
        }
        return null;
    }

    public static SelectList SelectListFor<T>(T selected) where T : struct 
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            var values = Enum.GetValues(t).Cast<Enum>()
                             .Select(e => new { Id = Convert.ToInt32(e), Name = e.GetDescription() });

            return new SelectList(values, "Id", "Name", Convert.ToInt32(selected));
        }
        return null;
    }

    public static string GetDescription<TEnum>(this TEnum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());

        if (fi != null)
        {
            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(
                    typeof(DescriptionAttribute),
                    false);

            if (attributes.Length > 0)
                return attributes[0].Description;
        }

        return value.ToString();
    }
}

This helper will enable you to convert an enum to a select list in just two lines.

In your controller:

ViewBag.TypeDropDown = EnumHelper.SelectListFor(field);

In your view:

@Html.DropDownList("TypeDropDown")
Sign up to request clarification or add additional context in comments.

5 Comments

But there isn't a method declared for DropDownFor?
Sorry, my mistake, it should be @Html.DropDownList("TypeDropDown"). I have updated my answer, thanks
Cheers, I changed the code a little to match into my class but it seems to work. I take it that this code won't automatically persist into my model (Like when using TextboxFor etc)
If you mean when posting a form, then yes, the selected value will be posted up to your action method as part of the viewmodel
Cool, I decided to grab the information with FormCollection in the end instead of grabbing the viewmodel. But that's due to the nature of my project. Thanks for the help!
1
public enum test
    {
        a = 0,
        b = 1
    }

then, put below in Html Extension

var options = Enum.GetValues(typeof(test))// u can pass type as parameter
.OfType<object>()
.Select(each => new {key = Enum.GetName(typeof(test), each), value = each})
.Select(each => string.Format("<option value=\"{1}\">{0}</option>", HttpUtility.HtmlEncode(each.key), each.value))
.Aggregate((cur, nex) => cur + nex);

return "<select name=...>"+options+"</select>";

1 Comment

this would be ok, except I need it to hook in with the display attribute in my MVC model like my code for RadioButtonFor
0

public class EnumExtensions
  {
    public static IEnumerable GetEnumSelectList()
    {
      return
        new SelectList(
          Enum.GetValues(typeof(T)).Cast().Select(
            x =>
            new
            {
              Value = x.ToString(),
              Text = x.ToString()
            }).ToList(),
        "Value",
        "Text");
    }
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.