Как создать выпадающий список из перечисления в ASP.NET MVC? - PullRequest
632 голосов
/ 23 декабря 2008

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

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

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

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

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

Ответы [ 36 ]

9 голосов
/ 24 марта 2014

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

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

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

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

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

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

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

8 голосов
/ 23 декабря 2008

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

7 голосов
/ 24 января 2014
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
6 голосов
/ 01 декабря 2011

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

Образец 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, является выбранным элементом.

5 голосов
/ 12 декабря 2011

Это версия для 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)
5 голосов
/ 29 января 2014

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

.

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

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

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

4 голосов
/ 24 мая 2013

Основываясь на ответе Саймона, похожий подход заключается в том, чтобы получить значения Enum для отображения из файла ресурсов, а не в атрибуте description в самом 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: фильм

Еще одна вещь, которую мне нравится делать, - вместо того, чтобы напрямую вызывать метод расширения, я бы предпочел вызывать его с помощью @ 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/

4 голосов
/ 08 ноября 2013

Ну, я действительно опаздываю на вечеринку, но для чего бы то ни было, я написал в блоге об этой самой теме, в результате чего я создаю класс 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() });
    }
}
3 голосов
/ 13 августа 2018

В .NET Core вы можете просто использовать это:

@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList<MyEnum>())
3 голосов
/ 04 февраля 2013

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...