Question Comment créer une liste déroulante à partir d'une énumération dans ASP.NET MVC?


J'essaie d'utiliser le Html.DropDownList méthode d'extension, mais ne peut pas comprendre comment l'utiliser avec une énumération.

Disons que j'ai une énumération comme celle-ci:

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

Comment puis-je créer une liste déroulante avec ces valeurs en utilisant Html.DropDownList méthode d'extension?

Ou est mon meilleur pari pour créer simplement une boucle for et créer les éléments Html manuellement?


586


origine


Réponses:


Pour MVC v5.1, utilisez Html.EnumDropDownListFor

@Html.EnumDropDownListFor(
    x => x.YourEnumField,
    "Select My Type", 
    new { @class = "form-control" })

Pour MVC v5, utilisez EnumHelper

@Html.DropDownList("MyType", 
   EnumHelper.GetSelectList(typeof(MyType)) , 
   "Select My Type", 
   new { @class = "form-control" })

Pour MVC 5 et inférieur

J'ai roulé la réponse de Rune dans une méthode d'extension:

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

Cela vous permet d'écrire:

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

par using MyApp.Common


732



Je sais que je suis en retard à la fête sur ce sujet, mais je pensais que vous pourriez trouver cette variante utile, car celle-ci vous permet également d'utiliser des chaînes descriptives plutôt que des constantes d'énumération dans le menu déroulant. Pour ce faire, décorez chaque entrée d'énumération avec un attribut [System.ComponentModel.Description].

Par exemple:

public enum TestEnum
{
  [Description("Full test")]
  FullTest,

  [Description("Incomplete or partial test")]
  PartialTest,

  [Description("No test performed")]
  None
}

Voici mon code:

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

Vous pouvez ensuite le faire à votre vue:

@Html.EnumDropDownListFor(model => model.MyEnumProperty)

J'espère que cela vous aide!

EDIT 2014-JAN-23: Microsoft vient de sortir MVC 5.1, qui a maintenant une fonctionnalité EnumDropDownListFor. Malheureusement, il ne semble pas respecter l'attribut [Description] donc le code ci-dessus est toujours valable. (Voir http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum pour les notes de publication de Microsoft.)

Mise à jour: Il soutient le Afficher attribut [Display(Name = "Sample")] cependant, donc on peut l'utiliser.

[Mise à jour - juste remarqué ceci, et le code ressemble à une version étendue du code ici: http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx, avec quelques ajouts. Si oui, l'attribution semblerait juste ;-)]


335



Dans ASP.NET MVC 5.1, ils ont ajouté EnumDropDownListFor() assistant, donc pas besoin d'extensions personnalisées:

Modèle:

public enum MyEnum
{
    [Display(Name = "First Value - desc..")]
    FirstValue,
    [Display(Name = "Second Value - desc...")]
    SecondValue
}

Vue:

@Html.EnumDropDownListFor(model => model.MyEnum)

Utilisation de Tag Helper (ASP.NET MVC 6):

<select asp-for="@Model.SelectedValue" asp-items="Html.GetEnumSelectList<MyEnum>()">

172



Je suis tombé sur le même problème, j'ai trouvé cette question et j'ai pensé que la solution fournie par Ash n'était pas ce que je cherchais; Avoir moi-même créer le HTML signifie moins de flexibilité par rapport à la version intégrée Html.DropDownList() fonction.

Il s'avère que C # 3 etc. rend cela plutôt facile. j'ai un enum appelé 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);

Cela crée un bon vieux SelectList cela peut être utilisé comme vous êtes habitué dans la vue:

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

Le type anonyme et LINQ rend cet IMHO tellement plus élégant. Aucune infraction prévue, Ash. :)


122



Voici une meilleure solution encapsulée:

http://www.spicelogic.com/Journal/ASP-NET-MVC-DropDownListFor-Html-Helper-Enum-5

Dites ici est votre modèle:

enter image description here

Exemple d'utilisation:

enter image description here

Interface utilisateur générée: enter image description here

Et généré HTML

enter image description here

Le coup de pouce du code source de l'extension Helper:

enter image description here

Vous pouvez télécharger l'exemple de projet à partir du lien que j'ai fourni.

EDIT: Voici le code:

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

53



Html.DropDownListFor ne nécessite qu'un IEnumerable, donc une alternative à la solution de Prize est la suivante. Cela vous permettra d'écrire simplement:

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

[Où SelectedItemType est un champ sur votre modèle de type ItemTypes, et votre modèle est non nul]

En outre, vous n'avez pas vraiment besoin de généraliser la méthode d'extension car vous pouvez utiliser enumValue.GetType () plutôt que typeof (T).

EDIT: Intégré la solution de Simon ici aussi, et inclus la méthode d'extension 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();
    }
}

46



Donc, sans fonctions d'extension si vous cherchez simple et facile .. C'est ce que j'ai fait

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

où XXXXX.Sites.YYYY.Models.State est une énumération

Probablement préférable de faire la fonction d'aide, mais quand le temps est court cela fera le travail.


31