Как создать выпадающий список из перечисления в ASP.NET MVC?

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

Допустим, у меня есть перечисление как это:

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

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

Или я лучше всего создаю цикл for и создаю элементы Html вручную?

23.12.2008 09:25:43
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();

по using MyApp.Common

835
26.08.2016 02:22:20
Я не мог заставить это работать, не могли бы вы помочь. Когда я делаю Post.PostType.ToSelectList (); это не признает расширение?
Barbaros Alp 18.12.2009 13:41:54
Я не мог заставить это работать тоже. Статус - это ваше свойство Enum для класса задач? Разве это не одно из перечисленных значений?
Daryl 5.07.2010 15:42:07
Вы можете немного ограничить это с помощью: где T: struct, IConvertible См .: stackoverflow.com/questions/79126/…
Richard Garside 17.05.2011 15:29:49
Это здорово. Если кто-то борется с реализацией, вот как я это сделал. Добавлен класс EnumHelpers в папку HtmlHelpers. Использовал приведенный выше код. Добавлено пространство имен в соответствии с рекомендацией @TodK: <add namespace = "xxx.HtmlHelpers" />. Затем я использовал его на странице бритвы, например: @ Html.DropDownListFor (model => model.Status, @ Model.Status.ToSelectList ()) HTH
Jeff Borden 25.07.2012 19:28:04
Обратите внимание, что в более новых ASP.NET MVCесть родной способ: stackoverflow.com/a/22295360/1361084
Ofiris 28.01.2015 16:22:27

Вы хотите посмотреть, используя что-то вроде Enum.GetValues

9
18.09.2018 09:50:42

ОБНОВЛЕНО - я бы предложил использовать предложение Руне ниже, а не эту опцию!


Я предполагаю, что вы хотите что-то вроде следующего выплюнул:

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

что вы можете сделать с помощью метода расширения что-то вроде следующего:

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();
}

НО такие вещи не локализуемы (то есть будет трудно перевести на другой язык).

Примечание: вам нужно вызвать статический метод с экземпляром перечисления, т.е. Html.DropdownEnum(ItemTypes.Movie);

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

-6
12.10.2009 09:06:29
Спасибо. Это на самом деле реализация, с которой я закончил, но я надеялся, что она уже встроена в платформу. Я думаю, нет. :-(
Kevin Pang 23.12.2008 22:05:42
В MvcContrib было что-то для этого, если я правильно помню.
Arnis Lapsa 12.10.2009 09:07:49
Я согласен с вашим обновлением - решения, опубликованные Rune & Prize, намного более аккуратны, оставляя фактическую разметку для отображения в представлении.
belugabob 12.10.2009 10:21:30

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

Оказывается, C # 3 и т. Д. Делает это довольно легко. Я enumпозвонил 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 делают это намного более элегантным ИМХО. Не обижайся, Эш. :)

130
29.03.2017 04:44:18
хороший ответ! Я надеялся, что кто-то будет использовать linq и SelectList :) Рад, что я проверил здесь первым!
Pure.Krome 22.03.2009 02:50:36
ID = s дают мне DataTextField, а не значение? В чем может быть причина? Спасибо
Barbaros Alp 18.12.2009 19:09:58
Руна, я использовал этот же метод, и DropDownList ОТСУТСТВУЕТ при рендеринге на сервер, но не сохраняет выбранное мной значение.
clockwiseq 23.11.2011 17:31:07
@BarbarosAlp Чтобы ID был числом, вам нужно привести перечисление к целому числу:select new { ID = (int)s, Name = s.ToString() };
Keith 1.12.2011 20:05:56
Это ответ, который мне нравится больше всего из-за его простоты. Жаль, что вы не получили достаточно кредитов, так как выбранный ответ использовал ваше решение.
anar khalilov 15.11.2013 09:07:19

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

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);
}

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

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

Обновление 23.10.12: добавлен параметр универсального типа для базового типа и исправлена ​​проблема некомпиляции, затрагивающая .NET 4+.

23
23.10.2012 16:04:59
Спасибо! Это был ответ, который мне был нужен. Я храню целочисленное значение Enum в виде столбца в базе данных, и это решение, похоже, работает отлично.
grimus 11.08.2010 06:40:46
но что если вы храните char, а не int? это мой случай. очевидно, я мог бы изменить (int) на (char), но как насчет того, чтобы сделать это также и универсальным. как это сделать?
Stefanvds 21.09.2010 12:46:34
@Stefandvds Это отличный вопрос относительно приведения к правильному представленному типу. Исходя из только что выполненных тестов, кажется, единственный способ добиться этого - указать фактический тип в качестве другого параметра типа. ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... }
Nathan Taylor 21.09.2010 13:19:11
Nathan Taylor 21.09.2010 14:11:05
Если значения вашего перечисления int, вы можете просто использовать Value = Convert.ToInt32(e). (int)eне компилируется :(
Andrew 29.04.2015 04:38:10

Для решения проблемы получения числа вместо текста используется метод расширения 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);
}
11
2.06.2010 21:48:03
Это то, что я искал, хотя это и ужаснее, чем я думал. Интересно , почему Visual Studio не позволит вам напрямую бросить eв int.
Andrew 29.04.2015 04:26:35
Или вы могли бы просто использовать ID = Convert.ToInt32(e).
Andrew 29.04.2015 04:39:45

Еще одно исправление этого метода расширения - текущая версия не выбирала текущее значение перечисления. Я исправил последнюю строку:

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());
    }
3
10.10.2010 01:27:31

Так что без функций расширения, если вы ищете простой и легкий .. Это то, что я сделал

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

где XXXXX.Sites.YYYY.Models.State - это перечисление

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

33
26.10.2010 17:13:06
Хорошо, это сработало, заполняя выпадающий список, но как установить выбранное по умолчанию значение в синтаксисе Razor для Html.DropDownListFor? Я хочу показать таблицу со списками перечислений, и мне нужно также установить выбранное значение в соответствии с тем, что было раньше.
Johncl 23.09.2011 14:20:31
Должен быть в состоянии передать второй параметр с выбранным значением в новую функцию SelectList (IEnumerable, object). Документация MSDN: msdn.microsoft.com/en-us/library/dd460123.aspx
Marty Trenouth 23.09.2011 17:26:46

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

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

[Где SelectedItemType - это поле в вашей модели типа ItemTypes, а ваша модель не равна нулю]

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

РЕДАКТИРОВАТЬ: интегрированное решение Саймона здесь, а также включил метод расширения 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();
    }
}
48
26.03.2012 09:42:36
У меня не работает ('System.NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта.') ... Моя 'Model' равна нулю ... вероятно, имеет отношение к 'GetNonNullableModelType', который есть у Саймона в комплекте
Learner 24.03.2012 20:31:39
@Cristi, вы правы, это решение не предназначено для использования в условиях, когда ваша Модель является нулевой. Я стараюсь избегать такого дизайна в целом и инициализирую для «пустой» модели, когда это так.
Zaid Masud 26.03.2012 09:43:23
Ну, я новичок в asp mvc, но у меня есть достаточно опыта в .Net. Спасибо, я посмотрю, что вы предлагаете. Кстати, ваше расширение ToDescription находится далеко за пределами области действия Enum. Я думаю, хорошо подходит для самого объекта. Это то, что я использовал, когда взял код Саймона и немного его очистил.
Learner 26.03.2012 20:05:58
@ Кристи, трудно понять, что вы подразумеваете под «далеко за пределами области действия Enum», но похоже, что вы говорите, что метод расширения ToDescription не является строго типизированным для перечисления ItemTypes? Это сделано намеренно и делает метод расширения универсальным для всех перечислений. Если вы сравниваете его с общим методом расширения, у каждого подхода есть свои плюсы и минусы. В частности, если вы генерируете rerecize, вы не можете ограничить только перечисления.
Zaid Masud 27.03.2012 11:26:22
Отлично, с благодарностью. Я изменил value.ToString, чтобы использовать расширение FromCamelCase, если не было описания. Вот так я катаюсь :)
Valamas 18.02.2013 01:41:59

Если вы хотите добавить поддержку локализации, просто измените метод s.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) - это ресурс, который вы хотите загрузить, а затем вы получите локализованную строку, также полезную, если ваш перечислитель имеет значения с несколькими словами.

3
12.11.2010 12:09:18

Это моя версия вспомогательного метода. Я использую это:

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);
    }
3
7.12.2010 11:07:10

Я знаю, что опоздал на вечеринку по этому вопросу, но подумал, что этот вариант может оказаться полезным, так как этот также позволяет вам использовать описательные строки, а не константы перечисления в раскрывающемся списке. Для этого украсьте каждую запись перечисления атрибутом [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)

Надеюсь, это поможет вам!

** РЕДАКТИРОВАТЬ 2014-ЯНВ-23: Microsoft только что выпустила MVC 5.1, которая теперь имеет функцию EnumDropDownListFor. К сожалению, он не соответствует атрибуту [Description], поэтому приведенный выше код остается в силе. См. Раздел Enum в примечаниях к выпуску Microsoft для MVC 5.1.

Обновление: хотя он поддерживает атрибут Display[Display(Name = "Sample")] , так что его можно использовать.

[Обновление - только что заметил это, и код выглядит как расширенная версия кода здесь: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- dropdownlist-helper-for-enums / , с парой дополнений. Если так, то атрибуция показалась бы честной ;-)]

359
18.09.2018 09:43:37
+1 Я нашел этот самый полезный из всех ответов здесь. Я смог превратить это в многократно используемый кусок кода. Спасибо!
Ed Charbeneau 19.07.2011 14:23:14
Visual Studio имеет странную ошибку, которая, если вы не ссылаетесь, System.Web.Mvc.Htmlговорит, что DropDownListForне может быть найдена, но и не может ее устранить. Вы должны сделать это вручную using System.Web.Mvc.Html;. Просто так ты знаешь.
Kezzer 27.10.2011 13:29:50
У меня есть вариант этого в сущности, который мы используем во всех наших проектах: gist.github.com/1287511
kamranicus 9.01.2012 18:45:09
Отличное решение, спасибо, было бы еще лучше, если бы вы могли кэшировать результаты GetEnumDescription
M. Mennan Kara 20.08.2012 13:52:13
Новый MVC 5.1 EnumDropDownListFor не использует [Description ("")], но использует [Display (Name = "")]! Наслаждайтесь :)
Supergibbs 28.02.2014 18:51:46

@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))
2
28.10.2011 08:21:09

Вы также можете использовать мои собственные HtmlHelpers в Griffin.MvcContrib. Следующий код:

@Html2.CheckBoxesFor(model => model.InputType) <br />
@Html2.RadioButtonsFor(model => model.InputType) <br />
@Html2.DropdownFor(model => model.InputType) <br />

Формирует:

введите описание изображения здесь

https://github.com/jgauffin/griffin.mvccontrib

3
28.10.2011 08:29:48

Это ответы Rune & Prize, измененные для использования intзначения Enum в качестве идентификатора.

Образец Enum:

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()) %>

Не забудьте импортировать пространство имен, содержащее метод Extension

<%@ 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является выбранным элементом.

7
1.12.2011 12:23:03
Или вы могли бы просто использовать Id = Convert.ToInt32(e).
Andrew 29.04.2015 04:44:07

Лучшее решение, которое я нашел для этого, объединяло этот блог с ответом Саймона Голдстоуна .

Это позволяет использовать 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);
        }
    }
}
11
18.09.2018 09:50:05
Это не работает, MVC 4 Razor. В представлении или во время выполнения error = "Вызов неоднозначен между следующими методами или свойствами LDN.Extensions.MvcExtensions.EnumDropDownListFor <MyModel, LDN.Models.YesPartialNoEnum?> (System.Web.Mvc.HtmlHelper <MyModel>, система .Linq.Expressions.Expression <System.Func <MyModel, LDN.Models.YesPartialNoEnum? >>) 'и .... "и тот же самый метод с теми же опорами повторяется снова (здесь недостаточно разрешенных символов).
Marc 14.09.2012 22:41:27

Это версия для Razor:

@{
    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)
6
12.12.2011 06:52:12
Это будет работать, только если ваше перечисление состоит из смежных значений, начинающихся с 0. Перечисление Flags не будет работать с этим. Творческое использование индексированного выбора, хотя.
Suncat2000 21.11.2018 13:34:42

Я закончил тем, что создал методы расширения, чтобы сделать то, что по сути является ответом здесь. Последняя половина Gist имеет дело именно с Enum.

https://gist.github.com/3813767

2
1.10.2012 19:14:51

Я опаздываю на этот раз, но я нашел действительно классный способ сделать это с помощью одной строки кода, если вы счастливы добавить пакет Unconstrained Melody NuGet (симпатичная небольшая библиотека от Jon Skeet).

Это решение лучше, потому что:

  1. Это гарантирует (с ограничениями общего типа), что значение действительно является значением перечисления (из-за Неограниченной Мелодии)
  2. Избегает ненужного бокса (из-за Неограниченной Мелодии)
  3. Он кэширует все описания, чтобы избежать использования отражения при каждом вызове (из-за неограниченной мелодии).
  4. Это меньше кода, чем другие решения!

Итак, вот шаги, чтобы заставить это работать:

  1. В консоли диспетчера пакетов "Install-Package UnconstrainedMelody"
  2. Добавьте свойство на вашей модели так:

    //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, используя это свойство в качестве источника.

4
18.09.2018 09:51:54
+1 за использование кода Джона Скита :), хотя, шучу, хорошо
Vamsi 8.02.2013 11:51:52

Вот лучшее инкапсулированное решение:

https://www.spicelogic.com/Blog/enum-dropdownlistfor-asp-net-mvc-5

Скажи, вот твоя модель:

введите описание изображения здесь

Пример использования:

введите описание изображения здесь

Сгенерированный интерфейс: введите описание изображения здесь

И сгенерированный HTML

введите описание изображения здесь

Снимок исходного кода расширения Helper:

введите описание изображения здесь

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

РЕДАКТИРОВАТЬ: Вот код:

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();
    }
}
63
18.09.2018 09:49:09
Просто мое мнение, но я думаю, что этот ответ намного чище, чем принятый ответ. Мне особенно нравится возможность использования атрибута Description. Я добавил код, чтобы люди могли копировать / вставлять его без загрузки.
Ben Mills 18.07.2013 20:31:51
Вызовите метод расширения как EnumDropDownListFor, а не DropDownListFor. Использование: -> @ Html.EnumDropDownListFor (x => x.Gender)
sandeep talabathula 13.07.2014 12:53:05
Для тех, кто ищет Добавление еще одного элемента «Пожалуйста, выберите» return htmlHelper.DropDownListFor (expression, createSelectList (expression.ReturnType, selected, firstElement), «Please Select»);
Sandeep 8.08.2014 21:22:31
Работает отлично! Однако на странице Подробности DisplayFor () показывает выбранное значение перечисления вместо соответствующего описания. Я предполагаю, что это вызывает перегрузку для DisplayFor () для типа enum. У кого-нибудь есть решение для этого?
corix010 21.01.2016 16:02:16

Основываясь на ответе Саймона, похожий подход заключается в том, чтобы значения Enum отображались из файла ресурсов, а не в атрибуте описания в самом Enum. Это полезно, если ваш сайт должен отображаться более чем на одном языке, и если у вас должен быть определенный файл ресурсов для Enums, вы можете пойти еще дальше и иметь только значения Enum в вашем Enum и ссылаться на них из расширения с помощью соглашение, такое как [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();
}

Ресурсы в файле Enums.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))
}

Если вас это интересует, я разместил гораздо более подробный ответ здесь в своем блоге:

http://paulthecyclist.com/2013/05/24/enum-dropdown/

5
24.05.2013 19:52:16
@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 ----"}
}
)
2
30.05.2013 10:10:44
@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" }

})
2
23.10.2013 09:57:03
Я думаю, что это неправильный ответ, он вообще не использует enum для заполнения выпадающего списка.
Andrew 30.04.2015 04:55:10

Ну, я действительно опаздываю на вечеринку, но для чего бы то ни было, я написал блог об этой самой теме, в результате чего я создал 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() });
    }
}
5
8.11.2013 12:44:00

1- Создайте свой ENUM

public enum LicenseType
{
    xxx = 1,
    yyy = 2
}

2- Создайте свой класс обслуживания

public class LicenseTypeEnumService
    {

        public static Dictionary<int, string> GetAll()
        {

            var licenseTypes = new Dictionary<int, string>();

            licenseTypes.Add((int)LicenseType.xxx, "xxx");
            licenseTypes.Add((int)LicenseType.yyy, "yyy");

            return licenseTypes;

        }

        public static string GetById(int id)
        {

            var q = (from p in this.GetAll() where p.Key == id select p).Single();
            return q.Value;

        }

    }

3- Установите ViewBag в вашем контроллере

var licenseTypes = LicenseTypeEnumService.GetAll();
ViewBag.LicenseTypes = new SelectList(licenseTypes, "Key", "Value");

4- Свяжите свой DropDownList

@Html.DropDownList("LicenseType", (SelectList)ViewBag.LicenseTypes)
0
15.01.2014 07:08:41
Вы вручную добавляете элементы перечисления ... Если ваше перечисление меняется, вам придется дважды изменить код. А что если у вас много перечислений для многих выпадающих списков?
Andrew 30.04.2015 04:56:44
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
8
24.01.2014 00:53:33
Хорошо! Как получить значение и текст из enum таким образом? Я имею в виду, что у меня есть SomeEnum {some1 = 1, some2 = 2}, мне нужно получить числа (1, 2) для значения и текст (some1, some2) для текста списка выбора
Dmitresky 5.03.2014 07:59:28

Теперь эта функция поддерживается из коробки в MVC 5.1 через @Html.EnumDropDownListFor()

Проверьте следующую ссылку:

https://docs.microsoft.com/en-us/aspnet/mvc/overview/releases/mvc51-release-notes#Enum

Это действительно позор, что Microsoft потребовалось 5 лет, чтобы реализовать такую ​​функцию, которая так востребована согласно голосованию выше!

6
18.09.2018 09:51:12

В ASP.NET MVC 5.1 они добавили EnumDropDownListFor()помощника, поэтому нет необходимости в пользовательских расширениях:

Модель :

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>()">
195
18.09.2018 09:44:20
Это нужно как-то поднять на первое место
user1752532 28.01.2015 16:02:40
Вы должны создать новый вопрос, относящийся к MVC 5.1, и указать его в качестве ответа, а затем отправить мне ссылку на сообщение, чтобы я мог добавить в избранное.
Kevin Heidt 29.03.2015 19:44:57
Что мне не нравится в EnumDropDownListFor (), так это то, что он сохраняет в БД значение int перечисления, а не текст, поэтому, если вы когда-нибудь решите добавить новый элемент перечисления, он обязательно должен идти в конце списка , чтобы не потерять связь сохраненных значений базы данных int с исходными позициями элементов перечисления. Это ненужное ограничение, если текст сохраняется. Кроме того, я предпочитаю смотреть на БД и видеть текст, а не на целые, где мне нужно искать текстовые значения в другом месте. В противном случае этот помощник HTML очень удобно использовать.
Giovanni 22.05.2015 15:57:30
@ Джованни - вы можете указать свои собственные числовые значения.
Tommy 24.01.2016 20:50:19
@Giovanni Строгий дизайн должен назначать значение для каждой записи перечисления (если это важно), в противном случае значение не должно иметь значения (и поэтому размещение новых в конце не должно быть проблемой). Сохранение значений int лучше, когда речь идет о сохранении памяти и повышении производительности (при выполнении некоторого поиска).
King King 4.11.2016 08:30:17

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

    enum Abc
    {
        [Description("Cba")]
        Abc,

        Def
    }


    public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, TEnum selectedValue)
    {
        IEnumerable<TEnum> values = Enum.GetValues(typeof(TEnum))
            .Cast<TEnum>();

        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var value in values)
        {
            string text = value.ToString();

            var member = typeof(TEnum).GetMember(value.ToString());
            if (member.Count() > 0)
            {
                var customAttributes = member[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (customAttributes.Count() > 0)
                {
                    text = ((DescriptionAttribute)customAttributes[0]).Description;
                }
            }

            items.Add(new SelectListItem
            {
                Text = text,
                Value = value.ToString(),
                Selected = (value.Equals(selectedValue))
            });
        }

        return htmlHelper.DropDownList(
            name,
            items
            );
    }

Надеюсь, это поможет.

3
18.09.2018 09:53:20
Я хочу вернуть член типа = DropdownList. У меня все хорошо с
Priyaranjan Anand Marathe 16.07.2019 20:55:04

Очень простой способ сделать это - без лишних расширений, которые кажутся излишними:

Ваше перечисление:

    public enum SelectedLevel
    {
       Level1,
       Level2,
       Level3,
       Level4
    }

Внутри вашего контроллера привязать Enum к списку:

    List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();

После этого бросьте его в ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Наконец, просто свяжите его с View:

    @Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class = "form-control" })

Это самый простой способ, который я нашел, и он не требует никаких расширений или чего-то такого безумного.

ОБНОВЛЕНИЕ : См. Комментарий Эндрюса ниже.

11
29.04.2015 22:28:07
Это работает только в том случае, если вы не присвоили никакое значение своему перечислению. Если бы вы имели Level1 = 1, то значение выпадающего будет "Level1"вместо 1.
Andrew 29.04.2015 04:43:17