Как создать раскрывающийся список из перечисления в ASP.NET MVC?
Я пытаюсь использовать Html.DropDownList
метод расширения, но не может понять, как использовать его с перечислением.
предположим, у меня есть такое перечисление:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
как мне создать раскрывающийся список с этими значениями, используя Html.DropDownList
метод расширения?
или лучше всего просто создать цикл for и создать элементы Html вручную?
30 ответов
для MVC v5.1 Используйте Html.EnumDropDownListFor
@Html.EnumDropDownListFor(
x => x.YourEnumField,
"Select My Type",
new { @class = "form-control" })
для MVC v5 используйте EnumHelper
@Html.DropDownList("MyType",
EnumHelper.GetSelectList(typeof(MyType)) ,
"Select My Type",
new { @class = "form-control" })
для MVC 5 и ниже
Я свернул ответ руны в метод расширения:
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();
by using MyApp.Common
Я знаю, что опаздываю на вечеринку, но подумал, что вы можете найти этот вариант полезным, так как этот также позволяет использовать описательные строки, а не константы перечисления в раскрывающемся списке. Чтобы сделать это, украсьте каждую запись перечисления [System.ComponentModel.Description] атрибут.
например:
public enum TestEnum
{
[Description("Full test")]
FullTest,
[Description("Incomplete or partial test")]
PartialTest,
[Description("No test performed")]
None
}
вот мой код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Reflection;
using System.ComponentModel;
using System.Linq.Expressions;
...
private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
{
Type realModelType = modelMetadata.ModelType;
Type underlyingType = Nullable.GetUnderlyingType(realModelType);
if (underlyingType != null)
{
realModelType = underlyingType;
}
return realModelType;
}
private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };
public static string GetEnumDescription<TEnum>(TEnum 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();
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
return EnumDropDownListFor(htmlHelper, expression, null);
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
items = SingleEmptyItem.Concat(items);
return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}
вы можете сделать это в своем представлении:
@Html.EnumDropDownListFor(model => model.MyEnumProperty)
надеюсь, это поможет ты!
**EDIT 2014-JAN-23: Microsoft только что выпустила MVC 5.1, который теперь имеет функцию EnumDropDownListFor. К сожалению, он, похоже, не уважает атрибут [Description], поэтому код выше все еще стоит.См.перечислить раздел в примечания к выпуску Microsoft для MVC 5.1.
Update: он поддерживает дисплей атрибут [Display(Name = "Sample")]
хотя, так что я могу использовать это.
[Update-только что заметил это, и код выглядит как расширенная версия кода здесь: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/с парой дополнений. Если это так, атрибуция будет казаться Справедливой ;-)]
In ASP.NET MVC 5.1, они добавили EnumDropDownListFor()
helper, поэтому нет необходимости в пользовательских расширениях:
модель:
public enum MyEnum
{
[Display(Name = "First Value - desc..")]
FirstValue,
[Display(Name = "Second Value - desc...")]
SecondValue
}
посмотреть:
@Html.EnumDropDownListFor(model => model.MyEnum)
использование Tag Helper (ASP.NET MVC 6):
<select asp-for="@Model.SelectedValue" asp-items="Html.GetEnumSelectList<MyEnum>()">
я столкнулся с той же проблемой, нашел этот вопрос и подумал, что решение, предоставленное Эшем, не было тем, что я искал; необходимость создавать HTML самостоятельно означает меньшую гибкость по сравнению со встроенным
вот лучшее инкапсулированное решение:
https://www.spicelogic.com/Blog/enum-dropdownlistfor-asp-net-mvc-5
скажем, вот ваша модель:
Пример Использования:
создается интерфейс:
и сгенерированный HTML
оснастка исходного кода вспомогательного расширения выстрел:
вы можете скачать образец проекта по ссылке, которую я предоставил.
EDIT: вот код:
public static class EnumEditorHtmlHelper
{
/// <summary>
/// Creates the DropDown List (HTML Select Element) from LINQ
/// Expression where the expression returns an Enum type.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
where TModel : class
{
TProperty value = htmlHelper.ViewData.Model == null
? default(TProperty)
: expression.Compile()(htmlHelper.ViewData.Model);
string selected = value == null ? String.Empty : value.ToString();
return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected));
}
/// <summary>
/// Creates the select list.
/// </summary>
/// <param name="enumType">Type of the enum.</param>
/// <param name="selectedItem">The selected item.</param>
/// <returns></returns>
private static IEnumerable<SelectListItem> createSelectList(Type enumType, string selectedItem)
{
return (from object item in Enum.GetValues(enumType)
let fi = enumType.GetField(item.ToString())
let attribute = fi.GetCustomAttributes(typeof (DescriptionAttribute), true).FirstOrDefault()
let title = attribute == null ? item.ToString() : ((DescriptionAttribute) attribute).Description
select new SelectListItem
{
Value = item.ToString(),
Text = title,
Selected = selectedItem == item.ToString()
}).ToList();
}
}
HTML-код.DropDownListFor требует только IEnumerable, поэтому альтернативой решению Prise является следующее. Это позволит вам просто написать:
@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())
[где SelectedItemType-это поле в вашей модели типов ItemTypes, а ваша модель-ненулевая]
Также, вы действительно не нужно genericize метод расширения, как вы можете использовать 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();
}
}
без функции расширения, если вы ищете простой и легкий.. Вот что я сделал!--2-->
<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>
где XXXXX.Места.YYYY.Модели.Состояние-это перечисление
вероятно, лучше сделать вспомогательную функцию, но когда времени мало, это позволит выполнить работу.
расширяя ответы Prise и Rune, если вы хотите, чтобы атрибут value элементов списка select отображался на целочисленное значение типа перечисления, а не строковое значение, используйте следующий код:
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, мы можем рассматривать его как объект, а затем привести его к integer, чтобы получить распакованное значение.
Примечание: Я также добавил ограничение универсального типа, чтобы ограничить типы для которое это расширение доступно только для структур (базовый тип перечисления) и проверки типа времени выполнения, которая гарантирует, что переданная структура действительно является перечислением.
обновление 10/23/12: Добавлен параметр универсального типа для базового типа и исправлена проблема не компиляции, влияющая на .NET 4+.
чтобы решить проблему получения числа вместо текста с помощью метода расширения Prise.
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);
}
супер простой способ сделать это-без всех вещей расширения, которые кажутся излишними, это:
ваши перечисления:
public enum SelectedLevel
{
Level1,
Level2,
Level3,
Level4
}
внутри вашего контроллера свяжите перечисление со списком:
List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();
после этого бросьте его в ViewBag:
ViewBag.RequiredLevel = new SelectList(myLevels);
наконец, просто привязать его к вид:
@Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class = "form-control" })
это, безусловно, самый простой способ я нашел, и не требует каких-либо расширений или что сумасшедший.
обновление: см. комментарий Эндрюса ниже.
лучшим решением, которое я нашел для этого, было объединение этот блог С ответ Саймона Голдстоуна.
Это позволяет использовать enum в модели. По сути, идея заключается в использовании целочисленного свойства, а также перечисления и эмуляции целочисленного свойства.
затем используйте [System.ComponentModel.Description] атрибут для аннотирования модели с отображаемым текстом и использовать расширение "EnumDropDownListFor" в вашем вид.
Это делает и представление и модель очень читаемыми и ремонтопригодными.
модель:
public enum YesPartialNoEnum
{
[Description("Yes")]
Yes,
[Description("Still undecided")]
Partial,
[Description("No")]
No
}
//........
[Display(Name = "The label for my dropdown list")]
public virtual Nullable<YesPartialNoEnum> CuriousQuestion{ get; set; }
public virtual Nullable<int> CuriousQuestionId
{
get { return (Nullable<int>)CuriousQuestion; }
set { CuriousQuestion = (Nullable<YesPartialNoEnum>)value; }
}
вид:
@using MyProject.Extensions
{
//...
@Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}
расширение (непосредственно из ответ Саймона Голдстоуна, включены здесь для полноты):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;
namespace MyProject.Extensions
{
//Extension methods must be defined in a static class
public static class MvcExtensions
{
private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
{
Type realModelType = modelMetadata.ModelType;
Type underlyingType = Nullable.GetUnderlyingType(realModelType);
if (underlyingType != null)
{
realModelType = underlyingType;
}
return realModelType;
}
private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };
public static string GetEnumDescription<TEnum>(TEnum 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();
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
return EnumDropDownListFor(htmlHelper, expression, null);
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
items = SingleEmptyItem.Concat(items);
return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}
}
}
вы хотите посмотреть на использование чего-то вроде Enum.GetValues
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
это руна & Prise ответы изменены, чтобы использовать перечисление int
значение в качестве ID.
Образец Перечисления:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
метод расширения:
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", (int)Enum.Parse(typeof(TEnum), enumObj.ToString()));
}
пример использования:
<%= Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>
Не забудьте импортировать пространство имен, содержащее метода расширения
<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>
образец сгенерированного HTML:
<select id="MyEnumList" name="MyEnumList">
<option value="1">Movie</option>
<option selected="selected" value="2">Game</option>
<option value="3">Book </option>
</select>
обратите внимание, что элемент, который вы используете для вызова ToSelectList
on-выбранный элемент.
Это версия для бритвы:
@{
var itemTypesList = new List<SelectListItem>();
itemTypesList.AddRange(Enum.GetValues(typeof(ItemTypes)).Cast<ItemTypes>().Select(
(item, index) => new SelectListItem
{
Text = item.ToString(),
Value = (index).ToString(),
Selected = Model.ItemTypeId == index
}).ToList());
}
@Html.DropDownList("ItemTypeId", itemTypesList)
теперь эта функция поддерживается из коробки в MVC 5.1 через @Html.EnumDropDownListFor()
проверьте следующие ссылки:
https://docs.microsoft.com/en-us/aspnet/mvc/overview/releases/mvc51-release-notes#Enum
это действительно позор, что Microsoft потребовалось 5 лет, чтобы реализовать такую функцию, которая так востребована в соответствии с голосованием выше!
основываясь на ответе Саймона, аналогичный подход заключается в том, чтобы получить значения перечисления для отображения из файла ресурсов, а не в атрибуте описания в самом перечислении. Это полезно, если ваш сайт должен быть отображен на нескольких языках, и если у вас должен быть конкретный файл ресурсов для перечислений, вы можете сделать еще один шаг вперед и иметь только значения перечисления в своем перечислении и ссылаться на них из расширения по соглашению, такому как [EnumName]_[EnumValue] - в конечном счете меньше печатаю!
расширение выглядит так:
public static IHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
var enumValues = Enum.GetValues(enumType).Cast<object>();
var items = from enumValue in enumValues
select new SelectListItem
{
Text = GetResourceValueForEnumValue(enumValue),
Value = ((int)enumValue).ToString(),
Selected = enumValue.Equals(metadata.Model)
};
return html.DropDownListFor(expression, items, string.Empty, null);
}
private static string GetResourceValueForEnumValue<TEnum>(TEnum enumValue)
{
var key = string.Format("{0}_{1}", enumValue.GetType().Name, enumValue);
return Enums.ResourceManager.GetString(key) ?? enumValue.ToString();
}
ресурсы в перечислениях.Файл resx, глядя, как ItemTypes_Movie: Film
еще одна вещь, которую я хотел бы сделать, это вместо вызова метода расширения напрямую, я бы предпочел вызвать его с помощью @Html.EditorFor(x => x.MyProperty), или в идеале просто иметь всю форму, в одном аккуратном @Html.EditorForModel(). Для этого я меняю шаблон строки, чтобы выглядеть так
@using MVCProject.Extensions
@{
var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;
@(typeof (Enum).IsAssignableFrom(type) ? Html.EnumDropDownListFor(x => x) : Html.TextBoxFor(x => x))
}
Если это вас интересует, Я поместил гораздо более подробный ответ здесь, в своем блоге:
Ну, я действительно опаздываю на вечеринку, но для чего это стоит, я написал в блоге об этой самой теме, в которой я создаю EnumHelper
класс, который обеспечивает очень простое преобразование.
http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23
в вашем контроллере:
//If you don't have an enum value use the type
ViewBag.DropDownList = EnumHelper.SelectListFor<MyEnum>();
//If you do have an enum value use the value (the value will be marked as selected)
ViewBag.DropDownList = EnumHelper.SelectListFor(MyEnum.MyEnumValue);
на ваш взгляд:
@Html.DropDownList("DropDownList")
@* OR *@
@Html.DropDownListFor(m => m.Property, ViewBag.DropDownList as SelectList, null)
вспомогательный класс:
public static class EnumHelper
{
// Get the value of the description attribute if the
// enum has one, otherwise use the value.
public static string GetDescription<TEnum>(this TEnum value)
{
var fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
{
return attributes[0].Description;
}
}
return value.ToString();
}
/// <summary>
/// Build a select list for an enum
/// </summary>
public static SelectList SelectListFor<T>() where T : struct
{
Type t = typeof(T);
return !t.IsEnum ? null
: new SelectList(BuildSelectListItems(t), "Value", "Text");
}
/// <summary>
/// Build a select list for an enum with a particular value selected
/// </summary>
public static SelectList SelectListFor<T>(T selected) where T : struct
{
Type t = typeof(T);
return !t.IsEnum ? null
: new SelectList(BuildSelectListItems(t), "Text", "Value", selected.ToString());
}
private static IEnumerable<SelectListItem> BuildSelectListItems(Type t)
{
return Enum.GetValues(t)
.Cast<Enum>()
.Select(e => new SelectListItem { Value = e.ToString(), Text = e.GetDescription() });
}
}
Я очень поздно, но я только что нашел классный способ сделать это с помощью одной строки кода, если вы счастливы, чтобы добавить Непринужденная Мелодия пакет NuGet (хорошая, небольшая библиотека от Джона Скита).
Это решение лучше, потому что:
- это гарантирует (с ограничениями общего типа), что значение действительно является значением перечисления (из-за неограниченной мелодии)
- он избегает ненужного бокса (из-за неограниченного Мелодия)
- он кэширует все описания, чтобы избежать использования отражения при каждом вызове (из-за неограниченной мелодии)
- это меньше кода, чем другие решения!
Итак, вот шаги, чтобы заставить это работать:
- В Консоли Диспетчера Пакетов "Install-Package UnconstrainedMelody"
-
добавьте свойство в свою модель следующим образом:
//Replace "YourEnum" with the type of your enum public IEnumerable<SelectListItem> AllItems { get { return Enums.GetValues<YourEnum>().Select(enumValue => new SelectListItem { Value = enumValue.ToString(), Text = enumValue.GetDescription() }); } }
теперь, когда у вас есть список SelectListItem в вашей модели вы можете использовать @Html.DropDownList или @Html.DropDownListFor использует это свойство в качестве источника.
еще одно исправление этого метода расширения-текущая версия не выбрала текущее значение перечисления. Я исправил последнюю строку:
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());
}
Если вы хотите добавить поддержку локализации, просто изменить С. метод toString() Для что-то вроде этого:
ResourceManager rManager = new ResourceManager(typeof(Resources));
var dayTypes = from OperatorCalendarDay.OperatorDayType s in Enum.GetValues(typeof(OperatorCalendarDay.OperatorDayType))
select new { ID = s, Name = rManager.GetString(s.ToString()) };
здесь typeof (Resources) - это ресурс, который вы хотите загрузить, а затем вы получаете локализованную строку, также полезную, если ваш перечислитель имеет значения с несколькими словами.
Это моя версия вспомогательного метода. Я использую это:
var values = from int e in Enum.GetValues(typeof(TEnum))
select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };
вместо этого:
var values = from TEnum e in Enum.GetValues(typeof(TEnum))
select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
, Name = e.ToString() };
вот это:
public static SelectList ToSelectList<TEnum>(this TEnum self) where TEnum : struct
{
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("self must be enum", "self");
}
Type t = typeof(TEnum);
var values = from int e in Enum.GetValues(typeof(TEnum))
select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };
return new SelectList(values, "ID", "Name", self);
}
вы также можете использовать мои пользовательские HtmlHelpers в Griffin.MvcContrib. Следующий код:
@Html2.CheckBoxesFor(model => model.InputType) <br />
@Html2.RadioButtonsFor(model => model.InputType) <br />
@Html2.DropdownFor(model => model.InputType) <br />
выдает:
@Simon Goldstone: Спасибо за ваше решение, оно может быть отлично применено в моем случае. Единственная проблема в том, что мне пришлось перевести его на VB. Но теперь это сделано, и чтобы сэкономить время других людей (в случае необходимости), я положил его здесь:
Imports System.Runtime.CompilerServices
Imports System.ComponentModel
Imports System.Linq.Expressions
Public Module HtmlHelpers
Private Function GetNonNullableModelType(modelMetadata As ModelMetadata) As Type
Dim realModelType = modelMetadata.ModelType
Dim underlyingType = Nullable.GetUnderlyingType(realModelType)
If Not underlyingType Is Nothing Then
realModelType = underlyingType
End If
Return realModelType
End Function
Private ReadOnly SingleEmptyItem() As SelectListItem = {New SelectListItem() With {.Text = "", .Value = ""}}
Private Function GetEnumDescription(Of TEnum)(value As TEnum) As String
Dim fi = value.GetType().GetField(value.ToString())
Dim attributes = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If Not attributes Is Nothing AndAlso attributes.Length > 0 Then
Return attributes(0).Description
Else
Return value.ToString()
End If
End Function
<Extension()>
Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum))) As MvcHtmlString
Return EnumDropDownListFor(htmlHelper, expression, Nothing)
End Function
<Extension()>
Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum)), htmlAttributes As Object) As MvcHtmlString
Dim metaData As ModelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
Dim enumType As Type = GetNonNullableModelType(metaData)
Dim values As IEnumerable(Of TEnum) = [Enum].GetValues(enumType).Cast(Of TEnum)()
Dim items As IEnumerable(Of SelectListItem) = From value In values
Select New SelectListItem With
{
.Text = GetEnumDescription(value),
.Value = value.ToString(),
.Selected = value.Equals(metaData.Model)
}
' If the enum is nullable, add an 'empty' item to the collection
If metaData.IsNullableValueType Then
items = SingleEmptyItem.Concat(items)
End If
Return htmlHelper.DropDownListFor(expression, items, htmlAttributes)
End Function
End Module
конец вы используете его так:
@Html.EnumDropDownListFor(Function(model) (model.EnumField))
Я закончил созданием методов расширения, чтобы сделать то, что по существу является ответом accept здесь. Последняя половина Gist имеет дело с перечислением конкретно.
@Html.DropdownListFor(model=model->Gender,new List<SelectListItem>
{
new ListItem{Text="Male",Value="Male"},
new ListItem{Text="Female",Value="Female"},
new ListItem{Text="--- Select -----",Value="-----Select ----"}
}
)
@Html.DropDownListFor(model => model.MaritalStatus, new List<SelectListItem>
{
new SelectListItem { Text = "----Select----", Value = "-1" },
new SelectListItem { Text = "Marrid", Value = "M" },
new SelectListItem { Text = "Single", Value = "S" }
})
здесь вариация Мартина Фаартофта, где вы можете поместить пользовательские метки, которые хороши для локализации.
public static class EnumHtmlHelper
{
public static SelectList ToSelectList<TEnum>(this TEnum enumObj, Dictionary<int, string> customLabels)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
var values = from TEnum e in Enum.GetValues(typeof(TEnum))
select new { Id = e, Name = customLabels.First(x => x.Key == Convert.ToInt32(e)).Value.ToString() };
return new SelectList(values, "Id", "Name", enumObj);
}
}
использовать в вид:
@Html.DropDownListFor(m => m.Category, Model.Category.ToSelectList(new Dictionary<int, string>() {
{ 1, ContactResStrings.FeedbackCategory },
{ 2, ContactResStrings.ComplainCategory },
{ 3, ContactResStrings.CommentCategory },
{ 4, ContactResStrings.OtherCategory }
}), new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Category)
Я сделал следующее и успешно работает:
- в поле зрения.cshtml по:
@модель MyModel.cs
@Html.EnumDropDownListFor(m=>m.MyItemType )
- в модели: MyModel.cs
public ItemTypes MyItemType { get; set; }