¿Cómo se crea una lista desplegable a partir de una enumeración en ASP.NET MVC?

Estoy tratando de usar el Html.DropDownList método de extensión pero no puedo averiguar cómo usarlo con una enumeración.

Digamos que tengo una enumeración como esta:

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

¿Cómo hago para crear un menú desplegable con estos valores usando el Html.DropDownList método de extensión?

¿O mi mejor opción es simplemente crear un bucle for y crear los elementos Html manualmente?

preguntado el 23 de diciembre de 08 a las 07:12

30 Respuestas

Para MVC v5.1 use Html.EnumDropDownListFor

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

Para MVC v5 use EnumHelper

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

Para MVC 5 y versiones inferiores

Envolví la respuesta de Rune en un método de extensión:

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

Esto le permite escribir:

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

by using MyApp.Common

Respondido 26 ago 16, 03:08

No pude hacer que funcionara, ¿podría ayudarme? Cuando hago Post.PostType.ToSelectList (); no reconoce la extensión? - Alpes bárbaros

Tampoco pude hacer que esto funcionara. ¿Status es su propiedad de enumeración en la clase de tarea? ¿No es este uno de los valores enumerados? - Daryl

Puede restringirlo un poco con: donde T: struct, IConvertible Ver: stackoverflow.com/questions/79126/… - Richard Garside

Esto es genial. Si alguien está luchando con la implementación, así es como lo hice. Se agregó una clase EnumHelpers a la carpeta HtmlHelpers. Usó el código anterior. Se agregó el espacio de nombres por recomendación de @TodK: . Luego lo usé en una página de afeitar como tal: @ Html.DropDownListFor (model => model.Status, @ Model.Status.ToSelectList ()) HTH - jeff borden

Tenga en cuenta que en los más nuevos ASP.NET MVC hay una forma nativa: stackoverflow.com/a/22295360/1361084 - Ofiris

Sé que llego tarde a la fiesta por esto, pero pensé que esta variante podría resultarle útil, ya que también le permite usar cadenas descriptivas en lugar de constantes de enumeración en el menú desplegable. Para hacer esto, decore cada entrada de enumeración con un atributo [System.ComponentModel.Description].

Por ejemplo:

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

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

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

Aquí está mi código:

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

Luego puede hacer esto en su vista:

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

¡Espero que esto te ayude!

** EDITAR 2014-JAN-23: Microsoft acaba de lanzar MVC 5.1, que ahora tiene una función EnumDropDownListFor. Lamentablemente, no parece respetar el atributo [Descripción], por lo que el código anterior sigue en pie. Enum sección en Notas de la versión de Microsoft para MVC 5.1.

Actualización: admite el Pantalla atributo [Display(Name = "Sample")] sin embargo, uno puede usar eso.

[Actualización: acabo de notar esto, y el código parece una versión extendida del código aquí: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/, con un par de adiciones. Si es así, la atribución parecería justa ;-)]

Respondido el 18 de Septiembre de 18 a las 10:09

+1 Encontré esta más útil de todas las respuestas aquí. Pude convertir esto en un código altamente reutilizable. ¡Gracias! - Ed Charbeneau

Visual Studio tiene un error extraño en el que si no hace referencia System.Web.Mvc.Html entonces dice que DropDownListFor no se puede encontrar, pero tampoco puede resolverlo. Tienes que hacerlo manualmente using System.Web.Mvc.Html;. Solo para saberlo. - Kezzer

Tengo una variante de esto en una esencia que usamos en todos nuestros proyectos: gist.github.com/1287511 - Kamranicus

Gran solución, gracias, sería incluso mejor si puede almacenar en caché los resultados de GetEnumDescription - M. Mennan Kara

¡El nuevo MVC 5.1 EnumDropDownListFor no usa [Description ("")] pero sí usa [Display (Name = "")]! Disfrutar :) - supergibbs

In ASP.NET MVC 5.1, agregaron el EnumDropDownListFor() helper, por lo que no se necesitan extensiones personalizadas:

Modelo:

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

Vea:

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

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

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

Respondido el 18 de Septiembre de 18 a las 10:09

Debe crear una nueva pregunta que sea específica de MVC 5.1 y poner esto como la respuesta, luego enviarme un enlace a la publicación para que pueda votar a favor de un favorito. - kevin heidt

Lo que no me gusta de EnumDropDownListFor () es que guarda en la base de datos el valor int de la enumeración, no el texto, por lo que si alguna vez elige agregar un nuevo elemento de enumeración, necesariamente debe ir al final de la lista , para no perder la relación de los valores int guardados de la base de datos con las posiciones originales de los elementos de enumeración. Esa es una restricción innecesaria si se guarda el texto. Además, prefiero poder mirar la base de datos y ver un texto, en lugar de ints donde luego tengo que buscar los valores de texto en otro lugar. De lo contrario, este ayudante html es muy conveniente de usar. - Juan

@Giovanni: puede especificar sus propios valores numéricos. - Tommy

aún no cena enum [Flags] :( - mejiamanuel57

@Giovanni El diseño estricto debe asignar un valor para cada entrada de enumeración (si es importante), de lo contrario, el valor no debería importar (por lo que colocar las nuevas al final no debería ser un problema). Guardar valores int es mejor cuando se trata de ahorrar almacenamiento y aumentar el rendimiento (cuando se realiza alguna búsqueda). - Rey rey

Me encontré con el mismo problema, encontré esta pregunta y pensé que la solución proporcionada por Ash no era la que estaba buscando; Tener que crear el HTML por mí mismo significa menos flexibilidad en comparación con el incorporado Html.DropDownList() función.

Resulta que C # 3, etc., hace que esto sea bastante fácil. Yo tengo un enum , que son 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);

Esto crea un buen ol ' SelectList que se puede usar como está acostumbrado en la vista:

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

El tipo anónimo y LINQ hace que esto sea mucho más elegante en mi humilde opinión. Sin intención de ofender, Ash. :)

respondido 29 mar '17, 05:03

¡buena respuesta! Esperaba que alguien usara linq y SelectList :) ¡Me alegro de haber verificado aquí primero! - Puro.Krome

ID = s me dan el DataTextField, no el valor? Cuál podría ser la razón ? Gracias - Alpes bárbaros

Rune, utilicé este mismo método y el DropDownList SÍ se procesa aún cuando se publica en el servidor, no guarda el valor que había seleccionado. - en el sentido de las agujas del reloj

@BarbarosAlp Para que ID sea un número, deberá convertir la enumeración en un int: select new { ID = (int)s, Name = s.ToString() }; - Keith

Esta es la respuesta que más me gusta por su sencillez. Es una pena que no haya recibido suficiente crédito ya que la respuesta seleccionada utilizó su solución. - anar jalilov

Aquí hay una mejor solución encapsulada:

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

Diga aquí está su modelo:

enter image description here

Uso de muestra:

enter image description here

IU generada: enter image description here

Y HTML generado

enter image description here

La instantánea del código fuente de la extensión auxiliar:

enter image description here

Puede descargar el proyecto de muestra desde el enlace que proporcioné.

EDITAR: Aquí está el código:

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

Respondido el 18 de Septiembre de 18 a las 10:09

Solo mi opinión, pero creo que esta respuesta es mucho más limpia que la respuesta aceptada. Particularmente me gusta la opción de usar el atributo Descripción. Agregué el código para que la gente pueda copiarlo / pegarlo sin descargarlo. - ben molinos

Llame al método de extensión como EnumDropDownListFor en lugar de DropDownListFor Usage: -> @ Html.EnumDropDownListFor (x => x.Gender) - sandeep talabathula

Para alguien que busca agregar un elemento más "Seleccione" return htmlHelper.DropDownListFor (expresión, createSelectList (expresión.ReturnType, selected, firstElement), "Por favor seleccione"); - Sandeep

¡Funciona bien! Sin embargo, en la página Detalles, DisplayFor () muestra el valor seleccionado de la enumeración en lugar de la descripción correspondiente. Supongo que esto requiere una sobrecarga para DisplayFor () para el tipo de enumeración. ¿Alguien tiene una solución para esto? - corix010

Html.DropDownListFor solo requiere un IEnumerable, por lo que una alternativa a la solución de Prise es la siguiente. Esto le permitirá simplemente escribir:

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

[Donde SelectedItemType es un campo en su modelo de tipo ItemTypes y su modelo no es nulo]

Además, no es necesario que genéricos el método de extensión, ya que puede utilizar enumValue.GetType () en lugar de typeof (T).

EDITAR: También integró la solución de Simon aquí, e incluyó el método de extensión 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();
    }
}

respondido 26 mar '12, 10:03

No funciona para mí ('System.NullReferenceException: referencia de objeto no establecida en una instancia de un objeto.') ... Mi 'Modelo' es nulo ... probablemente tenga algo que ver con 'GetNonNullableModelType' que Simon tiene incluido - Aprendiz

@Cristi, tienes razón, esta solución no está destinada a usarse en una condición en la que tu modelo sea nulo. Intento evitar un diseño de este tipo en general e inicializarlo en un modelo "vacío" cuando ese es el caso. - Zaid Masud

Bueno, soy nuevo en asp mvc, pero tengo bastante experiencia en .Net. Gracias, investigaré lo que estaba sugiriendo. Por cierto, su extensión ToDescription está muy fuera del alcance de 'Enum'. Supongo que va bien para el 'Objeto' en sí. Esto es lo que usé cuando tomé el código de Simon y lo limpié un poco más. - Aprendiz

@Cristi es difícil entender lo que quiere decir con "muy fuera del alcance de 'Enum'" pero parece que está diciendo que el método de extensión ToDescription no está fuertemente tipado en la enumeración ItemTypes. Esto es intencional y hace que el método de extensión sea utilizable genéricamente por todas las enumeraciones. Si lo está comparando con un método de extensión genérico, existen pros y contras de cada enfoque. En particular, si genereciza, no puede limitarlo solo a enumeraciones. - Zaid Masud

Genial, gracias. Cambié value.ToString para usar una extensión FromCamelCase en caso de que no hubiera una descripción. Así es como ruedo :) - Valamas

Así que sin funciones de extensión si lo que buscas es simple y fácil .. Esto es lo que hice

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

donde XXXXX.Sites.YYYY.Models.State es una enumeración

Probablemente sea mejor hacer la función de ayuda, pero cuando el tiempo es corto, esto hará el trabajo.

Respondido 26 Oct 10, 18:10

Bueno, esto funcionó al completar el menú desplegable, pero ¿cómo se configura el valor seleccionado predeterminado en la sintaxis de Razor para Html.DropDownListFor? Quiero mostrar una tabla con cuadros combinados de enumeraciones y también necesito establecer el valor seleccionado de acuerdo con lo que era antes. - Juancl

Debería poder pasar un segundo parámetro con el valor seleccionado a la nueva función SelectList (IEnumerable, object). Dococumentación de MSDN: msdn.microsoft.com/en-us/library/dd460123.aspx - marty trenouth

Ampliando las respuestas de Prize y Rune, si desea que el atributo value de los elementos de su lista de selección se asigne al valor entero del tipo Enumeration, en lugar del valor de la cadena, use el siguiente código:

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

En lugar de tratar cada valor de Enumeración como un objeto TEnum, podemos tratarlo como un objeto y luego convertirlo en entero para obtener el valor sin caja.

Nota: También agregué una restricción de tipo genérico para restringir los tipos para los cuales esta extensión está disponible solo para estructuras (tipo base de Enum), y una validación de tipo en tiempo de ejecución que asegura que la estructura pasada es de hecho una Enum.

Actualización 10 / 23 / 12: Se agregó un parámetro de tipo genérico para el tipo subyacente y se solucionó el problema de no compilación que afectaba a .NET 4+.

Respondido 23 Oct 12, 17:10

¡Gracias! Esta fue la respuesta que necesitaba. Estoy almacenando un valor entero de Enum como una columna en la base de datos y esta solución parece estar funcionando perfectamente. - grimus

pero ¿qué pasa si está almacenando un char y no un int? cual es mi caso. obviamente, podría cambiar (int) a (char), pero ¿qué tal hacer esto genérico también? ¿como hacer eso? - Stefanvds

@Stefandvds Esta es una gran pregunta con respecto a la conversión al tipo representado correcto. Según las pruebas que acabo de realizar, parecería que la única forma en que podría lograr esto sería especificando el tipo real como otro parámetro de tipo. ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... } - nathan taylor

Si los valores de su enumeración son int, simplemente puede usar Value = Convert.ToInt32(e). (int)e no se compila. :( - Andrés

Para resolver el problema de obtener el número en lugar del texto usando el método de extensión 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);
}

Respondido el 02 de junio de 10 a las 22:06

Eso es lo que estaba buscando, aunque es un poco más feo de lo que pensé que debía ser. Me pregunto por qué Visual Studio no te permitirá transmitir directamente e a int. - Andrés

O simplemente podría usar ID = Convert.ToInt32(e). - Andrés

Una manera súper fácil de hacer esto, sin todas las cosas de extensión que parecen excesivas, es esta:

Tu enumeración:

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

Dentro de su controlador, vincule el Enum a una lista:

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

Después de eso, tírelo a una ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Finalmente, simplemente vincúlelo a la Vista:

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

Esta es, con mucho, la forma más fácil que encontré y no requiere extensiones ni nada tan loco.

ACTUALIZACIÓN: Vea el comentario de Andrews a continuación.

Respondido 29 Abr '15, 23:04

Esto solo funciona si no ha asignado ningún valor a su enumeración. Si tuvieras Level1 = 1, entonces el valor del menú desplegable sería "Level1" en lugar de 1. - Andrés

La mejor solución que encontré para esto fue combinar este blog con La respuesta de Simon Goldstone.

Esto permite el uso de la enumeración en el modelo. Básicamente, la idea es usar una propiedad de número entero, así como la enumeración, y emular la propiedad de número entero.

Luego use el atributo [System.ComponentModel.Description] para anotar el modelo con su texto de visualización, y use una extensión "EnumDropDownListFor" en su vista.

Esto hace que tanto la vista como el modelo sean muy legibles y fáciles de mantener.

Modelo:

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

Vista

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

Extensión (directamente desde La respuesta de Simon Goldstone, incluido aquí para completar):

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

Respondido el 18 de Septiembre de 18 a las 10:09

Esto no funciona, MVC 4 Razor. En la vista o en tiempo de ejecución, error = "La llamada es ambigua entre los siguientes métodos o propiedades 'LDN.Extensions.MvcExtensions.EnumDropDownListFor (System.Web.Mvc.HtmlHelper , System.Linq.Expressions.Expression >) 'y .... "y exactamente el mismo método con los mismos accesorios repetidos nuevamente (no se permiten suficientes caracteres aquí). Marc

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

Respondido el 24 de enero de 14 a las 00:01

¡Bien! ¿Cómo obtener valor y texto de enum de esta manera? Quiero decir, tengo SomeEnum {some1 = 1, some2 = 2} Necesito obtener números (1, 2) para el valor y texto (some1, some2) para el texto de la lista de selección - Dmitresky

Quieres ver el uso de algo como Enum.GetValues

Respondido el 18 de Septiembre de 18 a las 10:09

En .NET Core, puede usar esto:

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

Respondido 12 ago 18, 23:08

O con el asistente de etiquetas <select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList<MyEnum>()"></select>. - Pascal R.

sí, diría que los ayudantes de etiquetas son incluso mejores ya que el formato está más cerca del HTML puro;) - Edad de oro

También puede hacer esto @ Html.DropDownListFor (x => x.Foo, Html.GetEnumSelectList (typeof (FooEnum))) - Fereydoon Barikzehy

Simple y lindo. TY! - Pratap Singh Mehra

respuesta impresionante. Estaba buscando no tener que crear un método personalizado para hacer esto - Cañón de Kolob

Estas son las respuestas de Runa y premio modificadas para usar la enumeración int valor como ID.

Ejemplo de enumeración:

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

Método de extensión:

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

Muestra de uso:

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

Recuerde importar el espacio de nombres que contiene el método de extensión

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

Muestra de HTML generado:

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

Tenga en cuenta que el elemento que utiliza para llamar al ToSelectList on es el elemento seleccionado.

Respondido el 01 de diciembre de 11 a las 12:12

O simplemente podría usar Id = Convert.ToInt32(e). - Andrés

Esta es la versión de 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)

Respondido el 12 de diciembre de 11 a las 06:12

Eso funcionará solo si su enumeración consta de valores contiguos que comienzan con 0. Una enumeración Flags no funcionaría con esto. Sin embargo, uso creativo del Select indexado. - Suncat2000

Ahora, esta función es compatible desde el primer momento en MVC 5.1 hasta @Html.EnumDropDownListFor()

Consulta el siguiente enlace:

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

Es una verdadera lástima que Microsoft haya tardado 5 años en implementar una característica tan solicitada según la votación anterior.

Respondido el 18 de Septiembre de 18 a las 10:09

Sobre la base de la respuesta de Simon, un enfoque similar es hacer que los valores de Enum se muestren desde un archivo de recursos, en lugar de en un atributo de descripción dentro del propio Enum. Esto es útil si su sitio necesita ser renderizado en más de un idioma y si tuviera un archivo de recursos específico para Enums, podría ir un paso más allá y tener solo valores de Enum, en su Enum y hacer referencia a ellos desde la extensión por una convención como [EnumName] _ [EnumValue] - ¡en última instancia, menos escritura!

La extensión entonces se ve así:

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

Recursos en el archivo Enums.Resx con aspecto de ItemTypes_Movie: Film

Otra cosa que me gusta hacer es, en lugar de llamar al método de extensión directamente, prefiero llamarlo con un @ Html.EditorFor (x => x.MyProperty), o idealmente solo tener el formulario completo, en un solo @ Html.EditorForModel (). Para hacer esto, cambio la plantilla de cadena para que se vea así

@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 esto le interesa, he puesto una respuesta mucho más detallada aquí en mi blog:

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

contestado el 24 de mayo de 13 a las 20:05

Bueno, llegué muy tarde a la fiesta, pero por lo que vale, he escrito en un blog sobre este mismo tema en el que creo un EnumHelper clase que permite una transformación muy fácil.

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

En tu controlador:

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

En tu opinión:

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

La clase de ayudante:

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

respondido 08 nov., 13:12

Llegué muy tarde en este pero encontré una manera realmente genial de hacer esto con una línea de código, si está contento de agregar el Melodía ilimitada Paquete NuGet (una bonita y pequeña biblioteca de Jon Skeet).

Esta solución es mejor porque:

  1. Asegura (con restricciones de tipo genérico) que el valor realmente es un valor de enumeración (debido a Melodía sin restricciones)
  2. Evita el boxeo innecesario (debido a Melodía sin restricciones)
  3. Almacena en caché todas las descripciones para evitar el uso de la reflexión en cada llamada (debido a Melodía sin restricciones)
  4. ¡Es menos código que las otras soluciones!

Entonces, estos son los pasos para que esto funcione:

  1. En la consola del Administrador de paquetes, "Install-Package UnconstrainedMelody"
  2. Agregue una propiedad en su modelo así:

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

Ahora que tiene la Lista de SelectListItem expuesta en su modelo, puede usar @ Html.DropDownList o @ Html.DropDownList para usar esta propiedad como fuente.

Respondido el 18 de Septiembre de 18 a las 10:09

+1 por usar el código de Jon Skeet :), aunque es una broma - Vamsi

Encontré una respuesta aquí. Sin embargo, algunas de mis enumeraciones tienen [Description(...)] atributo, así que modifiqué el código para brindar soporte para eso:

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

Espero que ayude.

Respondido el 18 de Septiembre de 18 a las 10:09

Quiero devolver un miembro de type = DropdownList. Soy bueno con Text = DescriptionAttribute pero me resulta difícil obtener el valor int de Value - rojobotelladesinfectante

Otra solución a este método de extensión: la versión actual no seleccionó el valor actual de la enumeración. Arreglé la última línea:

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

Respondido 10 Oct 10, 02:10

Si desea agregar soporte de localización, simplemente cambie el método s.toString () a algo como esto:

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

Aquí, el tipo de (Recursos) es el recurso que desea cargar, y luego obtiene la Cadena localizada, también útil si su enumerador tiene valores con varias palabras.

respondido 12 nov., 10:12

Esta es mi versión del método auxiliar. Yo uso esto:

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

En lugar de eso:

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

Aquí es:

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

Respondido el 07 de diciembre de 10 a las 11:12

También puede utilizar mis HtmlHelpers personalizados en Griffin.MvcContrib. El siguiente código:

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

Genera:

enter image description here

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

Respondido 28 Oct 11, 09:10

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

contestado el 30 de mayo de 13 a las 11:05

Me gustaría responder a esta pregunta de una manera diferente donde, el usuario no necesita hacer nada en controller or Linq expresión. De esta manera...

Tengo 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*/
    }

Ahora puedo simplemente crear un dropdown al usar esto 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 desea hacer un índice seleccionado, intente esto

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

Aquí he usado AccessLevelEnum.NoAccess como parámetro extra por defecto seleccionando el menú desplegable.

Respondido el 11 de Septiembre de 17 a las 10:09

@Simon Goldstone: Gracias por tu solución, se puede aplicar perfectamente en mi caso. El único problema es que tuve que traducirlo a VB. Pero ahora está hecho y para ahorrar tiempo a otras personas (en caso de que lo necesiten) lo pongo aquí:

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 Lo usas así:

@Html.EnumDropDownListFor(Function(model) (model.EnumField))

Respondido 28 Oct 11, 09:10

Terminé creando métodos de extensión para hacer lo que es esencialmente la respuesta de aceptación aquí. La última mitad de Gist trata específicamente de Enum.

https://gist.github.com/3813767

Respondido 01 Oct 12, 20:10

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

})

Respondido 23 Oct 13, 10:10

Creo que esta no es una respuesta válida, no está usando la enumeración en absoluto para completar el menú desplegable. - Andrés

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.