78

Imagine I have an enumeration such as this (just as an example):

public enum Direction{
    Horizontal = 0,
    Vertical = 1,
    Diagonal = 2
}

How can I write a routine to get these values into a System.Web.Mvc.SelectList, given that the contents of the enumeration are subject to change in future? I want to get each enumerations name as the option text, and its value as the value text, like this:

<select>
    <option value="0">Horizontal</option>
    <option value="1">Vertical</option>
    <option value="2">Diagonal</option>
</select>

This is the best I can come up with so far:

 public static SelectList GetDirectionSelectList()
 {
    Array values = Enum.GetValues(typeof(Direction));
    List<ListItem> items = new List<ListItem>(values.Length);

    foreach (var i in values)
    {
        items.Add(new ListItem
        {
            Text = Enum.GetName(typeof(Direction), i),
            Value = i.ToString()
        });
    }

    return new SelectList(items);
 }

However this always renders the option text as 'System.Web.Mvc.ListItem'. Debugging through this also shows me that Enum.GetValues() is returning 'Horizontal, Vertical' etc. instead of 0, 1 as I would've expected, which makes me wonder what the difference is between Enum.GetName() and Enum.GetValue().

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Lee D
  • 12,551
  • 8
  • 32
  • 34

12 Answers12

96

It's been awhile since I've had to do this, but I think this should work.

var directions = from Direction d in Enum.GetValues(typeof(Direction))
           select new { ID = (int)d, Name = d.ToString() };
return new SelectList(directions , "ID", "Name", someSelectedValue);
Brandon
  • 68,708
  • 30
  • 194
  • 223
  • 5
    Almost works, only needs a minor change! Your code will set the value to the Text when the OP wanted it to be an integer. Easy fix though. Change `ID = d` to `ID = (int)d`. Thanks for posting this, I never would have thought of it! – Christopher Apr 20 '10 at 06:06
  • Great answer, though I found that to pre-populate the dropdown, the value had to be the text representation of the enum, not the integer. – Luke Alderton Nov 25 '15 at 17:10
45

There is a new feature in ASP.NET MVC 5.1 for this.

http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum

@Html.EnumDropDownListFor(model => model.Direction)
Fred
  • 12,086
  • 7
  • 60
  • 83
34

This is what I have just made and personally I think its sexy:

 public static IEnumerable<SelectListItem> GetEnumSelectList<T>()
        {
            return (Enum.GetValues(typeof(T)).Cast<T>().Select(
                enu => new SelectListItem() { Text = enu.ToString(), Value = enu.ToString() })).ToList();
        }

I am going to do some translation stuff eventually so the Value = enu.ToString() will do a call out to something somewhere.

Dan
  • 12,808
  • 7
  • 45
  • 54
  • 1
    I'm having a problem with this code. The "Value" of the SelectList is the same as the "Text". When using Enums with EntityFramework, the value saved back to the database must be an int. – Northstrider Jul 12 '13 at 18:01
  • Ok, well do this then: Value = (int)enu – Dan Jul 15 '13 at 16:13
  • The reason (int)enu doesn't work in the example above is because the Value property of SelectListItem is a string not an integer. ((int)enu).ToString() will work. – Teppic Oct 17 '14 at 03:55
  • No it won't. In the example above, at compile time it doesn't know the type of `T`. As such, you can't cast to `int` like that. – ajbeaven Aug 17 '17 at 08:47
  • As from C# 7.3 you can now add 'where T : System.Enum'. – Johan Maes Jan 02 '19 at 10:06
28

To get the value of an enum you need to cast the enum to its underlying type:

Value = ((int)i).ToString();
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • Thanks! I thought about this but thought there might be a way to do it without casting. – Lee D Jul 10 '09 at 15:18
25

I wanted to do something very similar to Dann's solution, but I needed the Value to be an int and the text to be the string representation of the Enum. This is what I came up with:

public static IEnumerable<SelectListItem> GetEnumSelectList<T>()
    {
        return (Enum.GetValues(typeof(T)).Cast<int>().Select(e => new SelectListItem() { Text = Enum.GetName(typeof(T), e), Value = e.ToString() })).ToList();
    }
J.Noel.K
  • 251
  • 3
  • 3
16

In ASP.NET Core MVC this is done with tag helpers.

<select asp-items="Html.GetEnumSelectList<Direction>()"></select>
Fred
  • 12,086
  • 7
  • 60
  • 83
4

maybe not an exact answer to the question, but in CRUD scenarios i usually implements something like this:

private void PopulateViewdata4Selectlists(ImportJob job)
{
   ViewData["Fetcher"] = from ImportFetcher d in Enum.GetValues(typeof(ImportFetcher))
                              select new SelectListItem
                              {
                                  Value = ((int)d).ToString(),
                                  Text = d.ToString(),
                                  Selected = job.Fetcher == d
                              };
}

PopulateViewdata4Selectlists is called before View("Create") and View("Edit"), then and in the View:

<%= Html.DropDownList("Fetcher") %>

and that's all..

Carl Hörberg
  • 5,973
  • 5
  • 41
  • 47
4
return
            Enum
            .GetNames(typeof(ReceptionNumberType))
            .Where(i => (ReceptionNumberType)(Enum.Parse(typeof(ReceptionNumberType), i.ToString())) < ReceptionNumberType.MCI)
            .Select(i => new
            {
                description = i,
                value = (Enum.Parse(typeof(ReceptionNumberType), i.ToString()))
            });
Hamid
  • 962
  • 3
  • 9
  • 21
4

Or:

foreach (string item in Enum.GetNames(typeof(MyEnum)))
{
    myDropDownList.Items.Add(new ListItem(item, ((int)((MyEnum)Enum.Parse(typeof(MyEnum), item))).ToString()));
}
zkarolyi
  • 41
  • 1
3
    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() };
        //var values = from TEnum e in Enum.GetValues(typeof(TEnum)) select new { ID = e, Name = e.ToString() };

        return new SelectList(values, "ID", "Name", enumObj);
    }
    public static SelectList ToSelectList<TEnum>(this TEnum enumObj, string selectedValue) 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() };
        //var values = from TEnum e in Enum.GetValues(typeof(TEnum)) select new { ID = e, Name = e.ToString() };
        if (string.IsNullOrWhiteSpace(selectedValue))
        {
            return new SelectList(values, "ID", "Name", enumObj);
        }
        else
        {
            return new SelectList(values, "ID", "Name", selectedValue);
        }
    }
Joao Leme
  • 9,598
  • 3
  • 33
  • 47
3

I have more classes and methods for various reasons:

Enum to collection of items

public static class EnumHelper
{
    public static List<ItemDto> EnumToCollection<T>()
    {
        return (Enum.GetValues(typeof(T)).Cast<int>().Select(
            e => new ItemViewModel
                     {
                         IntKey = e,
                         Value = Enum.GetName(typeof(T), e)
                     })).ToList();
    }
}

Creating selectlist in Controller

int selectedValue = 1; // resolved from anywhere
ViewBag.Currency = new SelectList(EnumHelper.EnumToCollection<Currency>(), "Key", "Value", selectedValue);

MyView.cshtml

@Html.DropDownListFor(x => x.Currency, null, htmlAttributes: new { @class = "form-control" })
Miroslav Holec
  • 3,139
  • 25
  • 22
3

I had many enum Selectlists and, after much hunting and sifting, found that making a generic helper worked best for me. It returns the index or descriptor as the Selectlist value, and the Description as the Selectlist text:

Enum:

public enum Your_Enum
{
    [Description("Description 1")]
    item_one,
    [Description("Description 2")]
    item_two
}

Helper:

public static class Selectlists
{
    public static SelectList EnumSelectlist<TEnum>(bool indexed = false) where TEnum : struct
    {
        return new SelectList(Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(item => new SelectListItem
        {
            Text = GetEnumDescription(item as Enum),
            Value = indexed ? Convert.ToInt32(item).ToString() : item.ToString()
        }).ToList(), "Value", "Text");
    }

    // NOTE: returns Descriptor if there is no Description
    private static string GetEnumDescription(Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attributes != null && attributes.Length > 0)
            return attributes[0].Description;
        else
            return value.ToString();
    }
}

Usage: Set parameter to 'true' for indices as value:

var descriptorsAsValue = Selectlists.EnumSelectlist<Your_Enum>();
var indicesAsValue = Selectlists.EnumSelectlist<Your_Enum>(true);
RickL
  • 3,318
  • 10
  • 38
  • 39