Как создать выпадающий список из enum в ASP.NET MVC?
Я пытаюсь использовать метод расширения Html.DropDownList
, но не могу разобраться, как использовать его с перечислением.
Допустим, у меня есть перечисление, выглядящее следующим образом:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
Как мне создать выпадающий список с этими значениями, используя метод расширения Html.DropDownList
?
Или, возможно, лучший вариант — просто создать цикл for
и вручную создать элементы Html?
5 ответ(ов)
Для 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
.
Я столкнулся с такой же проблемой и нашел этот вопрос. Решение, предложенное Эшем, показалось мне не совсем тем, что мне нужно. Из-за необходимости создавать 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 делают это намного более элегантным, на мой взгляд. Без обид, Эш. 😃
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();
}
}
Таким образом, вы можете легко создать выпадающий список на основе вашего перечисления, используя описание прикрепленное к каждому элементу.
Если вы ищете простой и легкий способ сделать это без использования функций расширения, вот что я сделал:
<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State)))) %>
где XXXXX.Sites.YYYY.Models.State
— это перечисление (enum).
Возможно, лучше было бы сделать вспомогательную функцию, но когда времени в обрез, такой подход сработает.
Развивая ответы 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+.
Обнаружено потенциально опасное значение Request.Form, полученное от клиента
JavaScriptSerializer - Сериализация JSON перечислений в виде строк
Как установить заголовок Content-Type для запроса HttpClient?
Можно ли установить неограниченную длину для maxJsonLength в web.config?
Запрос прерван: Не удалось создать безопасный канал SSL/TLS