Come si associa un Enum a un controllo DropDownList in ASP.NET?


126

Diciamo che ho la seguente enumerazione semplice:

enum Response
{
    Yes = 1,
    No = 2,
    Maybe = 3
}

Come posso associare questo enum a un controllo DropDownList in modo che le descrizioni vengano visualizzate nell'elenco e recuperare il valore numerico associato (1,2,3) una volta selezionata un'opzione?

Risposte:


112

Probabilmente non legherei i dati in quanto è un enum e non cambierà dopo la compilazione (a meno che non stia avendo uno di quei momenti stoopid ).

Meglio solo scorrere l'enumerazione:

Dim itemValues As Array = System.Enum.GetValues(GetType(Response))
Dim itemNames As Array = System.Enum.GetNames(GetType(Response))

For i As Integer = 0 To itemNames.Length - 1
    Dim item As New ListItem(itemNames(i), itemValues(i))
    dropdownlist.Items.Add(item)
Next

O lo stesso in C #

Array itemValues = System.Enum.GetValues(typeof(Response));
Array itemNames = System.Enum.GetNames(typeof(Response));

for (int i = 0; i <= itemNames.Length - 1 ; i++) {
    ListItem item = new ListItem(itemNames[i], itemValues[i]);
    dropdownlist.Items.Add(item);
}

1
Grazie mille per questa risposta. GetType (risposta) non ha funzionato per me perché ricevo un'istanza della classe Enum, anziché la classe Enum. Quindi uso invece enumInstance.GetType ().
Sebastian

2
Utilizzando C #, non funziona per me, perché sia ​​getValues ​​che getNames restituiscono lo stesso, il primo come oggetti e il secondo come stringa. La definizione dell'enumerazione è così: public enum eResult {Right = 1, NoncontrolledError = 2,}
Javiere

9
A proposito in C #, non puoi accedere a Array con index itemNames [i], puoi farlo solo con arrayObject.GetValue (i) e in questo modo, restituisce solo il nome in entrambi i casi.
Javiere

1
Ho risolto mescolare questa soluzione con questo stackoverflow.com/questions/3213432/...
Javiere

5
Perché questo ha così tanti voti positivi. Il codice (almeno c #) ora funziona e contiene errori di sintassi.
Dave

69

Usa la seguente classe di utilità Enumerationper ottenere un IDictionary<int,string>(valore Enum e coppia di nomi) da un elenco ; quindi associ IDictionary a un controllo associabile.

public static class Enumeration
{
    public static IDictionary<int, string> GetAll<TEnum>() where TEnum: struct
    {
        var enumerationType = typeof (TEnum);

        if (!enumerationType.IsEnum)
            throw new ArgumentException("Enumeration type is expected.");

        var dictionary = new Dictionary<int, string>();

        foreach (int value in Enum.GetValues(enumerationType))
        {
            var name = Enum.GetName(enumerationType, value);
            dictionary.Add(value, name);
        }

        return dictionary;
    }
}

Esempio: utilizzo della classe di utilità per associare i dati di enumerazione a un controllo

ddlResponse.DataSource = Enumeration.GetAll<Response>();
ddlResponse.DataTextField = "Value";
ddlResponse.DataValueField = "Key";
ddlResponse.DataBind();

1
+1. L'ho usato, ma penso che la chiave e il valore siano nel verso sbagliato. Questo dovrebbe restituire un IDictionary <string, int>
Colin

Va notato che questo non si comporterà correttamente per tutti i tipi di enum (come uint, ulong, long, ecc.) Normalmente il campo più efficiente da cercare è la chiave. In questo caso, sarebbe int poiché gli interi sono un semplice confronto <, =,> rispetto a un confronto <e> di una stringa per ogni carattere.
Trisped

43

Lo uso per ASP.NET MVC :

Html.DropDownListFor(o => o.EnumProperty, Enum.GetValues(typeof(enumtype)).Cast<enumtype>().Select(x => new SelectListItem { Text = x.ToString(), Value = ((int)x).ToString() }))

36

La mia versione è solo una forma compressa di quanto sopra:

foreach (Response r in Enum.GetValues(typeof(Response)))
{
    ListItem item = new ListItem(Enum.GetName(typeof(Response), r), r.ToString());
    DropDownList1.Items.Add(item);
}

4
dovrebbe essere (int r in Enum.GetValues ​​(typeof (Response))) o vincolerà semplicemente la descrizione come nome e valore ...
Evan

2
questo non funziona, poiché inserisce il nome del membro dell'enumerazione nel valore di ListItem. La conversione in int funzionerebbe nella maggior parte dei casi, ma non se l'enum è uint, ulong o long.
Trisped

Soluzione molto migliore IMHO.
Vippy

23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Ogni tipo Enum deriva da System.Enum. Sono disponibili due metodi statici che consentono di associare i dati a un controllo elenco a discesa (e recuperare il valore). Questi sono Enum.GetNames e Enum.Parse. Utilizzando GetNames, puoi collegarti al tuo controllo elenco a discesa come segue:

protected System.Web.UI.WebControls.DropDownList ddColor;

private void Page_Load(object sender, System.EventArgs e)
{
     if(!IsPostBack)
     {
        ddColor.DataSource = Enum.GetNames(typeof(Color));
        ddColor.DataBind();
     }
}

Ora, se vuoi il valore Enum Back on Selection ...

  private void ddColor_SelectedIndexChanged(object sender, System.EventArgs e)
  {
    Color selectedColor = (Color)Enum.Parse(typeof(Color),ddColor.SelectedValue
  }

2
buona risposta ma un piccolo suggerimento: Color selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);
sma6871

11

Dopo aver letto tutti i post, ho trovato una soluzione completa per supportare la visualizzazione della descrizione dell'enumerazione nell'elenco a discesa e la selezione del valore corretto dal Modello nel menu a discesa durante la visualizzazione in modalità Modifica:

enum:

using System.ComponentModel;
public enum CompanyType
{
    [Description("")]
    Null = 1,

    [Description("Supplier")]
    Supplier = 2,

    [Description("Customer")]
    Customer = 3
}

classe di estensione enum:

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Mvc;

public static class EnumExtension
{
    public static string ToDescription(this System.Enum value)
    {
        var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this System.Enum enumValue)
    {
        return
            System.Enum.GetValues(enumValue.GetType()).Cast<T>()
                  .Select(
                      x =>
                      new SelectListItem
                          {
                              Text = ((System.Enum)(object) x).ToDescription(),
                              Value = x.ToString(),
                              Selected = (enumValue.Equals(x))
                          });
    }
}

Classe modello:

public class Company
{
    public string CompanyName { get; set; }
    public CompanyType Type { get; set; }
}

e Visualizza:

@Html.DropDownListFor(m => m.Type,
@Model.Type.ToSelectList<CompanyType>())

e se stai usando quel menu a discesa senza vincolarti a Model, puoi usare questo invece:

@Html.DropDownList("type",                  
Enum.GetValues(typeof(CompanyType)).Cast<CompanyType>()
.Select(x => new SelectListItem {Text = x.ToDescription(), Value = x.ToString()}))

Quindi, così facendo, puoi aspettarti che il tuo menu a discesa visualizzi la Descrizione invece dei valori enum. Anche quando si tratta di Modifica, il tuo modello verrà aggiornato dal valore selezionato a discesa dopo aver pubblicato la pagina.


1
Ben fatto, soprattutto la parte con le annotazioni [Descrizione]. Adotterò questa tecnica.
Baxter

Spiegazione pulita e ordinata. Kudos Amir !!

8

Come altri hanno già detto, non associare a un enum, a meno che non sia necessario associarlo a enumerazioni diverse a seconda della situazione. Ci sono diversi modi per farlo, un paio di esempi di seguito.

ObjectDataSource

Un modo dichiarativo per farlo con ObjectDataSource. Innanzitutto, crea una classe BusinessObject che restituirà l'elenco per associare DropDownList a:

public class DropDownData
{
    enum Responses { Yes = 1, No = 2, Maybe = 3 }

    public String Text { get; set; }
    public int Value { get; set; }

    public List<DropDownData> GetList()
    {
        var items = new List<DropDownData>();
        foreach (int value in Enum.GetValues(typeof(Responses)))
        {
            items.Add(new DropDownData
                          {
                              Text = Enum.GetName(typeof (Responses), value),
                              Value = value
                          });
        }
        return items;
    }
}

Quindi aggiungi un po 'di markup HTML alla pagina ASPX per puntare a questa classe BO:

<asp:DropDownList ID="DropDownList1" runat="server" 
    DataSourceID="ObjectDataSource1" DataTextField="Text" DataValueField="Value">
</asp:DropDownList>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    SelectMethod="GetList" TypeName="DropDownData"></asp:ObjectDataSource>

Questa opzione non richiede alcun codice dietro.

Codice dietro DataBind

Per ridurre a icona l'HTML nella pagina ASPX e eseguire il binding in Code Behind:

enum Responses { Yes = 1, No = 2, Maybe = 3 }

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        foreach (int value in Enum.GetValues(typeof(Responses)))
        {
            DropDownList1.Items.Add(new ListItem(Enum.GetName(typeof(Responses), value), value.ToString()));
        }
    }
}

Ad ogni modo, il trucco è lasciare che i metodi di tipo Enum di GetValues, GetNames ecc. Funzionino per te.


6

Non sono sicuro di come farlo in ASP.NET ma dai un'occhiata a questo post ... potrebbe aiutare?

Enum.GetValues(typeof(Response));

6

Potresti usare linq:

var responseTypes= Enum.GetNames(typeof(Response)).Select(x => new { text = x, value = (int)Enum.Parse(typeof(Response), x) });
    DropDownList.DataSource = responseTypes;
    DropDownList.DataTextField = "text";
    DropDownList.DataValueField = "value";
    DropDownList.DataBind();

5
Array itemValues = Enum.GetValues(typeof(TaskStatus));
Array itemNames = Enum.GetNames(typeof(TaskStatus));

for (int i = 0; i <= itemNames.Length; i++)
{
    ListItem item = new ListItem(itemNames.GetValue(i).ToString(),
    itemValues.GetValue(i).ToString());
    ddlStatus.Items.Add(item);
}

4
public enum Color
{
    RED,
    GREEN,
    BLUE
}

ddColor.DataSource = Enum.GetNames(typeof(Color));
ddColor.DataBind();

3

Codice generico utilizzando la risposta sei.

public static void BindControlToEnum(DataBoundControl ControlToBind, Type type)
{
    //ListControl

    if (type == null)
        throw new ArgumentNullException("type");
    else if (ControlToBind==null )
        throw new ArgumentNullException("ControlToBind");
    if (!type.IsEnum)
        throw new ArgumentException("Only enumeration type is expected.");

    Dictionary<int, string> pairs = new Dictionary<int, string>();

    foreach (int i in Enum.GetValues(type))
    {
        pairs.Add(i, Enum.GetName(type, i));
    }
    ControlToBind.DataSource = pairs;
    ListControl lstControl = ControlToBind as ListControl;
    if (lstControl != null)
    {
        lstControl.DataTextField = "Value";
        lstControl.DataValueField = "Key";
    }
    ControlToBind.DataBind();

}

3

Dopo aver trovato questa risposta, ho escogitato quello che penso sia un modo migliore (almeno più elegante) per farlo, ho pensato di tornare e condividerlo qui.

Load:

DropDownList1.DataSource = Enum.GetValues(typeof(Response));
DropDownList1.DataBind();

LoadValues:

Response rIn = Response.Maybe;
DropDownList1.Text = rIn.ToString();

SaveValues:

Response rOut = (Response) Enum.Parse(typeof(Response), DropDownList1.Text);

2

Questa è probabilmente una vecchia domanda .. ma è così che ho fatto la mia.

Modello:

public class YourEntity
{
   public int ID { get; set; }
   public string Name{ get; set; }
   public string Description { get; set; }
   public OptionType Types { get; set; }
}

public enum OptionType
{
    Unknown,
    Option1, 
    Option2,
    Option3
}

Quindi nella vista: ecco come utilizzare popolare il menu a discesa.

@Html.EnumDropDownListFor(model => model.Types, htmlAttributes: new { @class = "form-control" })

Questo dovrebbe popolare tutto nel tuo elenco enum. Spero che questo ti aiuti..


Tuttavia, questo funziona, è necessaria una classe di estensione se si desidera incorporare i valori letterali stringa con spazi.

1
Questa è la migliore risposta. @ Nikul, non hai bisogno di una classe di estensione. Devi solo usare le annotazioni. [Display(Name = "Option number one")] Option1,
rooter


1

Perché non usare in questo modo per poter passare ogni listControle:


public static void BindToEnum(Type enumType, ListControl lc)
        {
            // get the names from the enumeration
            string[] names = Enum.GetNames(enumType);
            // get the values from the enumeration
            Array values = Enum.GetValues(enumType);
            // turn it into a hash table
            Hashtable ht = new Hashtable();
            for (int i = 0; i < names.Length; i++)
                // note the cast to integer here is important
                // otherwise we'll just get the enum string back again
                ht.Add(names[i], (int)values.GetValue(i));
            // return the dictionary to be bound to
            lc.DataSource = ht;
            lc.DataTextField = "Key";
            lc.DataValueField = "Value";
            lc.DataBind();
        }
E l'uso è semplice come:

BindToEnum(typeof(NewsType), DropDownList1);
BindToEnum(typeof(NewsType), CheckBoxList1);
BindToEnum(typeof(NewsType), RadoBuuttonList1);


1

Da allora ASP.NET è stato aggiornato con alcune funzionalità in più e ora puoi utilizzare l'enumerazione incorporata per l'elenco a discesa.

Se vuoi associare l'Enum stesso, usa questo:

@Html.DropDownList("response", EnumHelper.GetSelectList(typeof(Response)))

Se stai vincolando a un'istanza di risposta, usa questo:

// Assuming Model.Response is an instance of Response
@Html.EnumDropDownListFor(m => m.Response)

0

Questa è la mia soluzione per Order an Enum and DataBind (Text and Value) to Dropdown using LINQ

var mylist = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList<MyEnum>().OrderBy(l => l.ToString());
foreach (MyEnum item in mylist)
    ddlDivisao.Items.Add(new ListItem(item.ToString(), ((int)item).ToString()));


0

Se desideri avere una descrizione più user friendly nella tua casella combinata (o altro controllo) puoi usare l'attributo Description con la seguente funzione:

    public static object GetEnumDescriptions(Type enumType)
    {
        var list = new List<KeyValuePair<Enum, string>>();
        foreach (Enum value in Enum.GetValues(enumType))
        {
            string description = value.ToString();
            FieldInfo fieldInfo = value.GetType().GetField(description);
            var attribute = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false).First();
            if (attribute != null)
            {
                description = (attribute as DescriptionAttribute).Description;
            }
            list.Add(new KeyValuePair<Enum, string>(value, description));
        }
        return list;
    }

Ecco un esempio di enumerazione con attributi di descrizione applicati:

    enum SampleEnum
    {
        NormalNoSpaces,
        [Description("Description With Spaces")]
        DescriptionWithSpaces,
        [Description("50%")]
        Percent_50,
    }

Quindi Bind per controllare in questo modo ...

        m_Combo_Sample.DataSource = GetEnumDescriptions(typeof(SampleEnum));
        m_Combo_Sample.DisplayMember = "Value";
        m_Combo_Sample.ValueMember = "Key";

In questo modo puoi inserire il testo che desideri nell'elenco a discesa senza che debba apparire come un nome di variabile


0

Puoi anche usare metodi di estensione. Per coloro che non hanno familiarità con le estensioni, suggerisco di controllare la documentazione di VB e C # .


Estensione VB:

Namespace CustomExtensions
    Public Module ListItemCollectionExtension

        <Runtime.CompilerServices.Extension()> _
        Public Sub AddEnum(Of TEnum As Structure)(items As System.Web.UI.WebControls.ListItemCollection)
            Dim enumerationType As System.Type = GetType(TEnum)
            Dim enumUnderType As System.Type = System.Enum.GetUnderlyingType(enumType)

            If Not enumerationType.IsEnum Then Throw New ArgumentException("Enumeration type is expected.")

            Dim enumTypeNames() As String = System.Enum.GetNames(enumerationType)
            Dim enumTypeValues() As TEnum = System.Enum.GetValues(enumerationType)

            For i = 0 To enumTypeNames.Length - 1
                items.Add(New System.Web.UI.WebControls.ListItem(saveResponseTypeNames(i), TryCast(enumTypeValues(i), System.Enum).ToString("d")))
            Next
        End Sub
    End Module
End Namespace

Per utilizzare l'estensione:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

Estensione C #:

namespace CustomExtensions
{
    public static class ListItemCollectionExtension
    {
        public static void AddEnum<TEnum>(this System.Web.UI.WebControls.ListItemCollection items) where TEnum : struct
        {
            System.Type enumType = typeof(TEnum);
            System.Type enumUnderType = System.Enum.GetUnderlyingType(enumType);

            if (!enumType.IsEnum) throw new Exception("Enumeration type is expected.");

            string[] enumTypeNames = System.Enum.GetNames(enumType);
            TEnum[] enumTypeValues = (TEnum[])System.Enum.GetValues(enumType);

            for (int i = 0; i < enumTypeValues.Length; i++)
            {
                items.add(new System.Web.UI.WebControls.ListItem(enumTypeNames[i], (enumTypeValues[i] as System.Enum).ToString("d")));
            }
        }
    }
}

Per utilizzare l'estensione:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Se si desidera impostare contemporaneamente l'elemento selezionato, sostituire

items.Add(New System.Web.UI.WebControls.ListItem(saveResponseTypeNames(i), saveResponseTypeValues(i).ToString("d")))

con

Dim newListItem As System.Web.UI.WebControls.ListItem
newListItem = New System.Web.UI.WebControls.ListItem(enumTypeNames(i), Convert.ChangeType(enumTypeValues(i), enumUnderType).ToString())
newListItem.Selected = If(EqualityComparer(Of TEnum).Default.Equals(selected, saveResponseTypeValues(i)), True, False)
items.Add(newListItem)

Convertendo in System.Enum invece che int dimensioni e problemi di output vengono evitati. Ad esempio 0xFFFF0000 sarebbe 4294901760 come uint ma sarebbe -65536 come int.

TryCast e as System.Enum sono leggermente più veloci di Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 nei miei test di velocità).



0

La soluzione accettata non funziona, ma il codice seguente aiuterà gli altri a cercare la soluzione più breve.

 foreach (string value in Enum.GetNames(typeof(Response)))
                    ddlResponse.Items.Add(new ListItem()
                    {
                        Text = value,
                        Value = ((int)Enum.Parse(typeof(Response), value)).ToString()
                    });

0

Puoi farlo molto più brevemente

public enum Test
    {
        Test1 = 1,
        Test2 = 2,
        Test3 = 3
    }
    class Program
    {
        static void Main(string[] args)
        {

            var items = Enum.GetValues(typeof(Test));

            foreach (var item in items)
            {
                //Gives you the names
                Console.WriteLine(item);
            }


            foreach(var item in (Test[])items)
            {
                // Gives you the numbers
                Console.WriteLine((int)item);
            }
        }
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.