asp.net - webform - my asp net mvc application




Come si crea un elenco a discesa da un enum in ASP.NET MVC? (20)

Per MVC v5.1 utilizzare Html.EnumDropDownListFor

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

Per MVC v5 utilizzare EnumHelper

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

Per MVC 5 e versioni precedenti

Ho lanciato la risposta di Rune in un metodo di estensione:

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

Questo ti permette di scrivere:

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

using MyApp.Common

Sto cercando di utilizzare il metodo di estensione Html.DropDownList ma non riesco a capire come usarlo con un'enumerazione.

Diciamo che ho un'enumerazione come questa:

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

Come faccio a creare un menu a discesa con questi valori utilizzando il metodo di estensione Html.DropDownList ?

O è la mia migliore scommessa per creare semplicemente un ciclo for e creare manualmente gli elementi Html?


Basandosi sulla risposta di Simon, un approccio simile è quello di far visualizzare i valori di Enum da un file di risorse, anziché in un attributo di descrizione all'interno dell'Enum stesso. Questo è utile se il tuo sito deve essere sottoposto a rendering in più di una lingua e se dovessi avere un file di risorse specifico per Enum, potresti fare un ulteriore passo avanti e avere solo valori Enum, nella tua Enum e farli riferimento dall'estensione di una convenzione come [EnumName] _ [EnumValue] - in definitiva meno digitando!

L'estensione quindi sembra:

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

Risorse nel file Enums.Resx simile a ItemTypes_Movie: Film

Un'altra cosa che mi piace fare è, invece di chiamare direttamente il metodo di estensione, preferisco chiamarlo con un @ Html.EditorFor (x => x.MyProperty), o idealmente avere solo l'intero modulo, in un modo ordinato @ Html.EditorForModel (). Per fare questo cambio il modello di stringa in modo che assomigli a questo

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

Se questo ti interessa, ho messo una risposta molto più dettagliata qui sul mio blog:

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


Ecco una soluzione meglio incapsulata:

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

Di 'qui il tuo modello:

Esempio di utilizzo:

Interfaccia utente generata:

E generato HTML

Istantanea del codice sorgente dell'estensione helper:

Puoi scaricare il progetto di esempio dal link che ho fornito.

EDIT: Ecco il codice:

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

Espandendo le risposte del premio e di Rune, se si desidera che l'attributo value degli elementi dell'elenco selezionato sia associato al valore intero del tipo Enumeration, anziché il valore stringa, utilizzare il seguente codice:

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

Invece di trattare ciascun valore di Enumerazione come oggetto TEnum, possiamo trattarlo come un oggetto e quindi convertirlo in numero intero per ottenere il valore unboxed.

Nota: ho anche aggiunto un vincolo di tipo generico per limitare i tipi per cui questa estensione è disponibile solo alle struct (il tipo di base di Enum) e una convalida del tipo run-time che garantisce che la struttura passata sia effettivamente un Enum.

Aggiornamento 23/10/12: Aggiunto parametro di tipo generico per tipo sottostante e problema di non compilazione fisso che interessa .NET 4+.


Html.DropDownListFor richiede solo un IEnumerable, quindi un'alternativa alla soluzione di Prize è la seguente. Questo ti permetterà di scrivere semplicemente:

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

[Dove SelectedItemType è un campo sul modello di tipo ItemTypes e il modello non è null]

Inoltre, non è necessario generalizzare il metodo di estensione in quanto è possibile utilizzare enumValue.GetType () anziché typeof (T).

EDIT: anche qui è stata integrata la soluzione di Simon e incluso il metodo di estensione 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();
    }
}

In ASP.NET MVC 5.1 , hanno aggiunto l' EnumDropDownListFor() , quindi non sono necessarie estensioni personalizzate:

Modello :

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

Visualizza :

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

Utilizzo di Tag Helper (ASP.NET MVC 6) :

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


Per risolvere il problema di ottenere il numero anziché il testo utilizzando il metodo di estensione del Premio.

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

Questa è la versione per 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)

Quindi, senza funzioni di estensione, se stai cercando semplice e facile .. Questo è quello che ho fatto

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

dove XXXXX.Sites.YYYY.Models.State è un enum

Probabilmente è meglio fare la funzione di aiuto, ma quando il tempo è breve questo lavoro farà.


Sono molto in ritardo su questo, ma ho appena trovato un modo davvero interessante per farlo con una riga di codice, se si è felici di aggiungere il pacchetto Melody NuGet Unconstrained (una piccola e bella libreria di Jon Skeet).

Questa soluzione è migliore perché:

  1. Assicura (con vincoli di tipo generico) che il valore è davvero un valore enum (dovuto a Melody non vincolato)
  2. Evita il pugilato inutile (a causa della melodia non vincolata)
  3. Memorizza nella cache tutte le descrizioni per evitare l'uso della riflessione su ogni chiamata (a causa della melodia non vincolata)
  4. È meno codice rispetto alle altre soluzioni!

Quindi, ecco i passaggi per farlo funzionare:

  1. Nella console di Package Manager, "Install-Package UnconstrainedMelody"
  2. Aggiungi una proprietà sul tuo modello in questo modo:

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

Ora che l'elenco di SelectListItem è stato esposto sul modello, è possibile utilizzare @ Html.DropDownList o @ Html.DropDownListFor utilizzando questa proprietà come origine.


Un modo super facile per ottenere questo risultato - senza tutte le estensioni che sembra eccessivo è questo:

Il tuo enum:

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

All'interno del controller, l'Enum viene associato a un elenco:

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

Dopo di ciò, gettalo in un ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Alla fine semplicemente legalo alla vista:

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

Questo è di gran lunga il modo più semplice che ho trovato e non richiede alcuna estensione o qualcosa di pazzesco.

AGGIORNAMENTO : Vedi il commento di Andrews qui sotto.


È inoltre possibile utilizzare i miei HtmlHelpers personalizzati in Griffin.MvcContrib. Il seguente codice:

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

genera:

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


Ecco una variazione di Martin Faartoft in cui è possibile inserire etichette personalizzate che sono carine per la localizzazione.

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

Utilizzare in vista:

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

Questa è la mia versione del metodo helper. Io uso questo:

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

Al posto di quello:

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

Ecco qui:

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

Se vuoi aggiungere il supporto per la localizzazione, modifica semplicemente il metodo s.toString () con qualcosa del genere:

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

Qui la typeof (Risorse) è la risorsa che si desidera caricare e quindi si ottiene la stringa localizzata, utile anche se il proprio enumeratore ha valori con più parole.


Ho finito col creare metodi di estensione per fare ciò che essenzialmente è la risposta accettata qui. L'ultima metà del Gist si occupa specificamente di Enum.

https://gist.github.com/3813767


Ho trovato una risposta https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/ . Tuttavia, alcune delle mie enumerazioni hanno [Description(...)]attributo, quindi ho modificato il codice per fornire supporto per questo:

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

Spero che sia d'aiuto.


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

})

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






asp.net-mvc