7

Как создать выпадающий список из enum в ASP.NET MVC?

1

Я пытаюсь использовать метод расширения Html.DropDownList, но не могу разобраться, как использовать его с перечислением.

Допустим, у меня есть перечисление, выглядящее следующим образом:

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

Как мне создать выпадающий список с этими значениями, используя метод расширения Html.DropDownList?

Или, возможно, лучший вариант — просто создать цикл for и вручную создать элементы Html?

5 ответ(ов)

9

Для MVC v5.1 используйте Html.EnumDropDownListFor

@Html.EnumDropDownListFor(
    x => x.YourEnumField,
    "Выберите мой тип", 
    new { @class = "form-control" })

Для MVC v5 используйте EnumHelper

@Html.DropDownList("MyType", 
   EnumHelper.GetSelectList(typeof(MyType)), 
   "Выберите мой тип", 
   new { @class = "form-control" })

Для MVC 5 и ниже

Я объединил ответ Rune в метод расширения:

namespace MyApp.Common
{
    public static class MyExtensions {
        public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        {
            var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                         select new { Id = e, Name = e.ToString() };
            return new SelectList(values, "Id", "Name", enumObj);
        }
    }
}

Теперь вы можете использовать следующую запись:

ViewData["taskStatus"] = task.Status.ToSelectList();

не забудьте подключить пространство имен using MyApp.Common.

1

Я столкнулся с такой же проблемой и нашел этот вопрос. Решение, предложенное Эшем, показалось мне не совсем тем, что мне нужно. Из-за необходимости создавать HTML вручную я терял гибкость по сравнению с встроенной функцией Html.DropDownList().

Оказалось, что в C# 3.0 и выше это делается довольно просто. У меня есть перечисление 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);

Это создает хороший старый SelectList, который можно использовать так, как вы привыкли в представлении:

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

Анонимный тип и LINQ делают это намного более элегантным, на мой взгляд. Без обид, Эш. 😃

0

Html.DropDownListFor требует лишь IEnumerable, поэтому альтернативой решению Prise будет следующее. Это позволит вам просто записать:

@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())

[Где SelectedItemType — это поле в вашей модели типа ItemTypes, и ваша модель не равна null].

Также вам не обязательно обобщать метод расширения, так как вы можете использовать enumValue.GetType() вместо typeof(T).

EDIT: Интегрировал решение Simon и добавил метод расширения ToDescription.

public static class EnumExtensions
{
    public static IEnumerable<SelectListItem> ToSelectList(this Enum enumValue)
    {
        return from Enum e in Enum.GetValues(enumValue.GetType())
               select new SelectListItem
               {
                   Selected = e.Equals(enumValue),
                   Text = e.ToDescription(),
                   Value = e.ToString()
               };
    }

    public static string ToDescription(this Enum value)
    {
        var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
}

Таким образом, вы можете легко создать выпадающий список на основе вашего перечисления, используя описание прикрепленное к каждому элементу.

0

Если вы ищете простой и легкий способ сделать это без использования функций расширения, вот что я сделал:

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

где XXXXX.Sites.YYYY.Models.State — это перечисление (enum).

Возможно, лучше было бы сделать вспомогательную функцию, но когда времени в обрез, такой подход сработает.

0

Развивая ответы Prise и Rune, если вы хотите, чтобы значение атрибута вашего списка выбора соответствовало целочисленному значению типа перечисления, а не строковому значению, используйте следующий код:

public static SelectList ToSelectList<T, TU>(T enumObj) 
    where T : struct
    where TU : struct
{
    if(!typeof(T).IsEnum) throw new ArgumentException("Enum is required.", "enumObj");

    var values = from T e in Enum.GetValues(typeof(T))
                 select new { 
                    Value = (TU)Convert.ChangeType(e, typeof(TU)),
                    Text = e.ToString() 
                 };

    return new SelectList(values, "Value", "Text", enumObj);
}

Вместо того чтобы рассматривать каждое значение перечисления как объект типа TEnum, мы можем рассматривать его как объект и затем привести его к целому числу, чтобы получить разыменованное значение.

Примечание: Я также добавил ограничение на обобщенные типы, чтобы ограничить типы, для которых это расширение доступно, только структурами (базовый тип Enum), и добавил проверку типа во время выполнения, которая гарантирует, что переданная структура действительно является перечислением.

Обновление 23.10.12: Добавлен обобщенный параметр типа для базового типа и исправлена проблема с компиляцией для .NET 4+.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь