web-dev-qa-db-fra.com

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

J'essaie d'utiliser la méthode d'extension Html.DropDownList mais je ne vois pas 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 créer un menu déroulant avec ces valeurs à l'aide de la méthode d'extension Html.DropDownList?

Ou est-il préférable de simplement créer une boucle for et de créer les éléments HTML manuellement?

644
Kevin Pang

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 transformé la réponse de Rune en 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

808
Martin Faartoft

Je sais que je suis en retard, mais je pense que cette variante pourrait être utile, car elle 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 alors le faire à votre avis:

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

J'espère que cela vous aide!

** EDIT 2014-JAN-23: Microsoft vient de publier MVC 5.1, qui possède désormais une fonctionnalité EnumDropDownListFor. Malheureusement, il ne semble pas respecter l'attribut [Description], aussi le code ci-dessus est-il toujours valide. Voir section Enum dans Notes de publication de Microsoft pour MVC 5.1.

Update: Il supporte l'attribut Display[Display(Name = "Sample")], donc on peut l'utiliser.

[Mise à jour - je viens de le remarquer et le code ressemble à une version étendue du code ici: https://blogs.msdn.Microsoft.com/stuartleeks/2010/05/21/asp-net-mvc- creation-a-dropdownlist-helper-for-enums / , avec quelques ajouts. Si oui, l'attribution semblerait juste ;-)]

350
SimonGoldstone

Dans ASP.NET MVC 5.1, ils ont ajouté le helper EnumDropDownListFor(), vous n'avez donc pas besoin d'extensions personnalisées:

Modèle :

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

Voir :

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

à l'aide de Tag Helper (ASP.NET MVC 6) :

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

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

Il s'avère que C # 3 etc. rend cela assez 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 qui peut être utilisé comme vous en avez l'habitude dans la vue:

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

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

127
Rune Jacobsen

Voici une meilleure solution encapsulée:

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

Dites voici 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 HTML généré

enter image description here

La capture instantanée de code source du Helper Extension:

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

Html.DropDownListFor ne requiert qu'un IEnumerable, une alternative à la solution de Prise est donc 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]

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

EDIT: La solution de Simon a également été intégrée ici, ainsi que 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();
    }
}
47
Zaid Masud

Donc, sans fonctions d'extension si vous recherchez 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 un enum

Il est probablement préférable d’utiliser la fonction d’assistance, mais lorsque le temps est compté, le travail est fait.

32
Marty Trenouth

En développant les réponses Prize et Rune, si vous souhaitez que l'attribut value de vos éléments de la liste de sélection soit mis en correspondance avec la valeur entière du type Enumeration, plutôt que la valeur de la chaîne, utilisez le code suivant:

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

Au lieu de traiter chaque valeur d'énumération comme un objet TEnum, nous pouvons le traiter comme un objet, puis le convertir en entier pour obtenir la valeur non encadrée.

Remarque: J'ai également ajouté une contrainte de type générique pour limiter les types pour lesquels cette extension est disponible à des structures uniquement (type de base d'Enum), ainsi qu'une validation de type à l'exécution garantissant que la structure transmise est En effet, un Enum.

Mise à jour le 23/10/12: Ajout d'un paramètre de type générique pour le type sous-jacent et un problème résolu de non-compilation affectant .NET 4+.

22
Nathan Taylor

La meilleure solution que j'ai trouvée pour cela consistait à combiner ce blog avec réponse de Simon Goldstone .

Cela permet d'utiliser l'énum dans le modèle. L'idée est essentiellement d'utiliser une propriété entière ainsi que l'énumération et d'émuler la propriété entière.

Utilisez ensuite l'attribut [System.ComponentModel.Description] pour annoter le modèle avec votre texte d'affichage et utilisez une extension "EnumDropDownListFor" dans votre vue.

Cela rend la vue et le modèle très lisibles et maintenables.

Modèle:

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

Vue:

@using MyProject.Extensions
{
//...
    @Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}

Extension (directement de réponse de Simon Goldstone , incluse ici pour complément):

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);
        }
    }
}
10
Nick Evans

Pour résoudre le problème de l'obtention du numéro au lieu du texte, utilisez la méthode d'extension de 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);
}
10
ceedee

Un moyen très facile de faire cela - sans toutes les extensions qui semblent excessives est la suivante:

Votre enum:

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

À l’intérieur de votre contrôleur, liez l’énumération à une liste:

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

Après cela, jetez-le dans un ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Enfin, simplement le lier à la vue:

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

C'est de loin le moyen le plus simple que j'ai trouvé et qui ne nécessite aucune extension ou quoi que ce soit de fou.

UPDATE: Voir le commentaire Andrews ci-dessous.

9
Louie Bacaj

Vous voulez utiliser quelque chose comme Enum.GetValues

8
Garry Shutler
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
7
Mr. Pumpkin

Les réponses de Rune & Prize ont été modifiées pour utiliser la valeur Enum int en tant qu'ID.

Exemple d'énumération:

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

Méthode d'extension:

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

Exemple d'utilisation:

 <%=  Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>

N'oubliez pas d'importer l'espace de noms contenant la méthode d'extension

<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>

Exemple de HTML généré:

<select id="MyEnumList" name="MyEnumList">
    <option value="1">Movie</option>
    <option selected="selected" value="2">Game</option>
    <option value="3">Book </option>
</select>

Notez que l’élément que vous utilisez pour appeler ToSelectList est l’élément sélectionné.

6
Mr. Flibble

Ceci est la version pour 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
user550950

Désormais, cette fonctionnalité est prise en charge dans MVC 5.1 via @Html.EnumDropDownListFor()

Vérifiez le lien suivant:

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

Il est vraiment dommage qu’il ait fallu 5 ans à Microsoft pour mettre en oeuvre une telle fonctionnalité, très demandée par le vote ci-dessus!

5
Lafi

Eh bien, je suis vraiment en retard pour la fête, mais pour ce que cela vaut, j’ai écrit un blog sur ce sujet même dans lequel je crée une classe EnumHelper qui permet une transformation très facile.

http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enen-in-mvc-and-c%2

Dans votre contrôleur:

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

Dans votre vue:

@Html.DropDownList("DropDownList")
@* OR *@
@Html.DropDownListFor(m => m.Property, ViewBag.DropDownList as SelectList, null)

La classe d'assistance:

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

S'appuyant sur la réponse de Simon, une approche similaire consiste à obtenir les valeurs Enum à afficher à partir d'un fichier de ressources, plutôt que dans un attribut description au sein de l'énum lui-même. Ceci est utile si votre site doit être restitué dans plusieurs langues et si vous aviez un fichier de ressources spécifique pour Enums, vous pourriez aller plus loin et ne placer que des valeurs Enum dans votre énumération et les référencer depuis l'extension par une convention telle que [EnumName] _ [EnumValue] - finalement moins de frappe!

L'extension ressemble alors à:

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

Ressources dans le fichier Enums.Resx ressemblant à ItemTypes_Movie: Film

Une autre chose que j'aime faire est qu'au lieu d'appeler directement la méthode d'extension, je l'appellerais plutôt avec un @ Html.EditorFor (x => x.MyProperty) ou, idéalement, tout le formulaire, dans un @ Html.EditorForModel (). Pour ce faire, je modifie le modèle de chaîne pour qu'il ressemble à ceci

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

Si cela vous intéresse, j'ai mis une réponse beaucoup plus détaillée ici sur mon blog:

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

4
PaulTheCyclist

Je suis très en retard sur celui-ci, mais je viens de trouver un moyen vraiment cool de le faire avec une seule ligne de code, si vous êtes heureux d'ajouter le package nconstrained Melody NuGet (une jolie petite bibliothèque de Jon Skeet).

Cette solution est meilleure car:

  1. Cela garantit (avec des contraintes de type génériques) que la valeur est vraiment une valeur enum (due à une mélodie non contrainte)
  2. Cela évite la boxe inutile (à cause de la mélodie sans contrainte)
  3. Il met en cache toutes les descriptions pour éviter d'utiliser la réflexion sur chaque appel (en raison de la mélodie sans contrainte)
  4. C'est moins de code que les autres solutions!

Alors, voici les étapes pour que cela fonctionne:

  1. Dans la console du gestionnaire de packages, "Install-Package UnconstrainedMelody"
  2. Ajoutez une propriété sur votre modèle comme ceci:

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

Maintenant que vous avez la liste des SelectListItem exposée sur votre modèle, vous pouvez utiliser @ Html.DropDownList ou @ Html.DropDownListFor en utilisant cette propriété comme source.

3
nootn

J'ai trouvé une réponse ici . Cependant, certaines de mes énumérations ont l'attribut [Description(...)], j'ai donc modifié le code pour fournir un support pour cela:

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

J'espère que ça t'as aidé.

3
Alkasai

Dans .NET Core, vous pouvez simplement utiliser ceci:

@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList<MyEnum>())
3
GoldenAge

Vous pouvez également utiliser mes HtmlHelpers personnalisés dans Griffin.MvcContrib. Le code suivant:

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

Génère:

enter image description here

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

2
jgauffin

Si vous souhaitez ajouter un support de localisation, modifiez simplement la méthode s.toString () comme suit:

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

Ici, le typeof (Ressources) est la ressource que vous voulez charger, puis vous obtenez la chaîne localisée, également utile si votre énumérateur a des valeurs avec plusieurs mots.

2
brafales

Ceci est ma version de la méthode d'assistance. J'utilise ceci:

var values = from int e in Enum.GetValues(typeof(TEnum))
             select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };

Au lieu de:

var values = from TEnum e in Enum.GetValues(typeof(TEnum))
           select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
                     , Name = e.ToString() };

C'est ici:

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);
    }
2
Vadim Sentiaev

Un autre correctif pour cette méthode d'extension - la version actuelle n'a pas sélectionné la valeur actuelle de l'énum. J'ai corrigé la dernière ligne:

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

Je voudrais répondre à cette question différemment, l'utilisateur ne doit rien faire dans l'expression controller ou Linq. Par ici...

J'ai un ENUM

public enum AccessLevelEnum
    {
        /// <summary>
        /// The user cannot access
        /// </summary>
        [EnumMember, Description("No Access")]
        NoAccess = 0x0,

        /// <summary>
        /// The user can read the entire record in question
        /// </summary>
        [EnumMember, Description("Read Only")]
        ReadOnly = 0x01,

        /// <summary>
        /// The user can read or write
        /// </summary>
        [EnumMember, Description("Read / Modify")]
        ReadModify = 0x02,

        /// <summary>
        /// User can create new records, modify and read existing ones
        /// </summary>
        [EnumMember, Description("Create / Read / Modify")]
        CreateReadModify = 0x04,

        /// <summary>
        /// User can read, write, or delete
        /// </summary>
        [EnumMember, Description("Create / Read / Modify / Delete")]
        CreateReadModifyDelete = 0x08,

        /*/// <summary>
        /// User can read, write, or delete
        /// </summary>
        [EnumMember, Description("Create / Read / Modify / Delete / Verify / Edit Capture Value")]
        CreateReadModifyDeleteVerify = 0x16*/
    }

Maintenant, je peux simplement créer un dropdown en utilisant ce enum.

@Html.DropDownList("accessLevel",new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class = "form-control" })

OR

@Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class = "form-control" })

Si vous voulez faire un index sélectionné, essayez ceci

@Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum)) , AccessLevelEnum.NoAccess ),new { @class = "form-control" })

Ici, j'ai utilisé AccessLevelEnum.NoAccess comme paramètre supplémentaire pour la sélection par défaut du menu déroulant.

1
gdmanandamohon
@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" }

})
1
vicky
@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 ----"}
}
)
1
Shahnawaz

J'ai fini par créer des méthodes d'extention pour faire ce qui est essentiellement la réponse acceptée ici. La dernière moitié du Gist traite spécifiquement d’Enum.

https://Gist.github.com/3813767

1
Nick Albrecht

Voici une variante de Martin Faartoft où vous pouvez mettre des étiquettes personnalisées, ce qui est bien pour la localisation.

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

Utiliser en vue:

@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)
1
Rushino
        ////  ViewModel

        public class RegisterViewModel
          {

        public RegisterViewModel()
          {
              ActionsList = new List<SelectListItem>();
          }

        public IEnumerable<SelectListItem> ActionsList { get; set; }

        public string StudentGrade { get; set; }

           }

       //// Enum Class

        public enum GradeTypes
             {
               A,
               B,
               C,
               D,
               E,
               F,
               G,
               H
            }

         ////Controller action 

           public ActionResult Student()
               {
    RegisterViewModel vm = new RegisterViewModel();
    IEnumerable<GradeTypes> actionTypes = Enum.GetValues(typeof(GradeTypes))
                                         .Cast<GradeTypes>();                  
    vm.ActionsList = from action in actionTypes
                     select new SelectListItem
                     {
                         Text = action.ToString(),
                         Value = action.ToString()
                     };
              return View(vm);
               }

         ////// View Action

   <div class="form-group">
                            <label class="col-lg-2 control-label" for="hobies">Student Grade:</label>
                            <div class="col-lg-10">
                               @Html.DropDownListFor(model => model.StudentGrade, Model.ActionsList, new { @class = "form-control" })
                            </div>
1
shuvo sarker

Dans MVC4, je voudrais faire comme ceci

@Html.DropDownList("RefType", new SelectList(Enum.GetValues(typeof(WebAPIApp.Models.RefType))), " Select", new { @class = "form-control" })

public enum RefType
    {
        Web = 3,
        API = 4,
        Security = 5,
        FE = 6
    }

    public class Reference
    {
        public int Id { get; set; }
        public RefType RefType { get; set; }
    }
1
PAWAN RAJ Shakya

J'ai fait ce qui suit et fonctionne avec succès:

  • Dans le view.cshtml:

@model MyModel.cs

@Html.EnumDropDownListFor(m=>m.MyItemType )
  • Dans le modèle: MyModel.cs

public ItemTypes MyItemType { get; set; }

1
MarwaAhmad

@Simon Goldstone: Merci pour votre solution, elle peut parfaitement être appliquée dans mon cas. Le seul problème est que je devais le traduire en VB. Mais maintenant, c'est fait et pour sauver le temps des autres (au cas où ils en auraient besoin), je le mets ici:

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

Fin Vous l'utilisez comme ceci:

@Html.EnumDropDownListFor(Function(model) (model.EnumField))
1
Michal B.

1- Créez votre ENUM

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

2- Créez votre classe de service

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- Placez le ViewBag dans votre contrôleur

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

4- Liez votre DropDownList

@Html.DropDownList("LicenseType", (SelectList)ViewBag.LicenseTypes)
0
Mohammad Karimi