tags:

views:

5829

answers:

10

I'm trying to use the Html.DropDownList extension method but can't figure out how to use it with an enumeration.

Let's say I have an enumeration like this:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

How do I go about creating a dropdown with these values using the Html.DropDownList extension method? Or is my best bet to simply create a for loop and create the html elements manually?

+2  A: 

You want to look at using something like Enum.GetValues

Garry Shutler
A: 

UPDATED - I would suggest using the suggestion by Rune below rather than this option!


I assume that you want something like the following spat out:

<select name="blah">
    <option value="1">Movie</option>
    <option value="2">Game</option>
    <option value="3">Book</option>
</select>

which you could do with an extension method something like the following:

public static string DropdownEnum(this System.Web.Mvc.HtmlHelper helper,
                                  Enum values)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append("<select name=\"blah\">");
    string[] names = Enum.GetNames(values.GetType());
    foreach(string name in names)
    {
        sb.Append("<option value=\"");
        sb.Append(((int)Enum.Parse(values.GetType(), name)).ToString());
        sb.Append("\">");
        sb.Append(name);
        sb.Append("</option>");
    }
    sb.Append("</select>");
    return sb.ToString();
}

BUT things like this aren't localisable (i.e. it will be hard to translate into another language).

Note: you need to call the static method with an instance of the Enumeration, i.e. Html.DropdownEnum(ItemTypes.Movie);

There may be a more elegant way of doing this, but the above does work.

Ash
Thanks. That's actually the implementation I ended up with but I was hoping it was already baked into the framework. I guess not. :-(
Kevin Pang
wow. thats fugly.
fregas
There was something in MvcContrib for this if i remember correct.
Arnis L.
belugabob
+34  A: 

I bumped into the same problem, found this question, and thought that the solution provided by Ash wasn't what I was looking for; Having to create the HTML myself means less flexibility compared to the built-in Html.DropDownList() function.

Turns out C#3 etc. makes this pretty easy. I have an Enum called TaskStatus:

var statuses = from TaskStatus s in Enum.GetValues(typeof(TaskStatus))
               select new { ID = s, Name = s.ToString() };
ViewData["taskStatus"] = new SelectList(statuses, "ID", "Name", task.Status);

This creates a good ol' SelectList that can be used like you're used to in the view:

<td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr>

The anonymous type and LINQ makes this so much more elegant IMHO. No offence intended, Ash. :)

Rune Jacobsen
good answer! i was hoping someone would use linq and the SelectList :) Glad i checked here first!
Pure.Krome
ID = s give me the DataTextField not the value ? What might be the reason ? Thank you
Barbaros Alp
+49  A: 

I rolled Rune's answer into an extension method:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
  var values = from TEnum e in Enum.GetValues(typeof(TEnum))
               select new { ID = e, Name = e.ToString() };

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

This allows you to write:

ViewData["taskStatus"] = task.Status.ToSelectList();
Prise
Excellent! Thank you.
Brad Mellen-Crandell
Awesome, just what I was looking for!
Kyle LeNeau
I couldnt get it worked, could you please help. When i do Post.PostType.ToSelectList(); it doesnt recognise the extension ?
Barbaros Alp
I could not get this to work either. Is Status your Enum Property on the task class? Isn't this one of the enumerated values?
Daryl
A: 

Hi,

i tried Prise's solution and it seems really cool, i only met an important problem. In the selectList given by this extension method, the DataValue are not the indexes of the constants in the enum, but the same as DataText. I have :

<select id="type" name="type">
<option value="Item1">Item1</option>
<option selected="selected" value="Item2">Item2</option>
<option value="Item3">Item3</option>
</select>

and i would like to have :

<select id="type" name="type">
<option value="1">Item1</option>
<option selected="selected" value="2">Item2</option>
<option value="3">Item3</option>
</select>

Thank you for helping

Proviste
+4  A: 

Expanding on Prise and Rune's answers, if you'd like to have the value attribute of your select list items map to the integer value of the Enumeration type, rather than the string value, use the following code:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj) where TEnum : struct {
    if(!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

    var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                 select new { ID = (int)e, Name = e.ToString() };

    return new SelectList(values, "ID", "Name", enumObj);
}

Instead of treating each Enumeration value as a TEnum object, we can treat it as a object and then cast it to integer to get the unboxed value.

Note: I also added a generic type constraint to restrict the types for which this extension is available to only structs (Enum's base type), and a run-time type validation which ensures that the struct passed in is indeed an Enum.

Nathan Taylor
Thanks! This was the answer I needed. I'm storing an Enum's integer value as a column in the database and this solution seems to be working perfectly.
grimus
but what if you are storing a char and not an int? which is my case. obviously i could change (int) to (char) but how about making this generic as well. how to do that?
Stefanvds
@Stefandvds This is a great question in regards to casting to the correct represented type. Based on the tests I just performed it would seem the only way you would be able to achieve this would be by specifying the actual type as another type parameter. `ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... }`
Nathan Taylor
@Stefandvds [See this question](http://stackoverflow.com/questions/3760933/how-to-determine-the-represented-type-of-enum-value/3760973).
Nathan Taylor
+2  A: 

To solve the problem of getting the number instead of text using Prise's extension method.

public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
  var values = from TEnum e in Enum.GetValues(typeof(TEnum))
               select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
                         , Name = e.ToString() };

  return new SelectList(values, "Id", "Name", enumObj);
}
ceedee
A: 

Another fix to this extension method - the current version didn't select the enum's current value. I fixed the last line:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                       select new
                       {
                           ID = (int)Enum.Parse(typeof(TEnum), e.ToString()),
                           Name = e.ToString()
                       };


        return new SelectList(values, "ID", "Name", ((int)Enum.Parse(typeof(TEnum), enumObj.ToString())).ToString());
    }
justabuzz
A: 

So without Extension functions if you are looking for simple and easy.. This is what I did

<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>

where XXXXX.Sites.YYYY.Models.State is an enum

Probably better to do helper function, but when time is short this will get the job done.

Marty Trenouth