Wie binde ich eine Aufzählung an ein DropDownList-Steuerelement in ASP.NET?

126

Angenommen, ich habe die folgende einfache Aufzählung:

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

Wie kann ich diese Aufzählung an ein DropDownList-Steuerelement binden, damit die Beschreibungen in der Liste angezeigt werden und der zugehörige numerische Wert (1,2,3) abgerufen wird, sobald eine Option ausgewählt wurde?

Strahl
quelle

Antworten:

112

Ich würde die Daten wahrscheinlich nicht binden , da es sich um eine Aufzählung handelt, und sie wird sich nach der Kompilierungszeit nicht ändern (es sei denn, ich habe einen dieser dummen Momente).

Besser nur durch die Aufzählung iterieren:

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

Oder dasselbe 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);
}
Mark Glorie
quelle
1
Vielen Dank für diese Antwort. GetType (Response) hat bei mir nicht funktioniert, da ich eine Instanz der Enum-Klasse anstelle der Enum-Klasse erhalte. Also verwende ich stattdessen enumInstance.GetType ().
Sebastian
2
Mit C # funktioniert es bei mir nicht, da sowohl getValues ​​als auch getNames dasselbe zurückgeben, das erste wie Objekte und das zweite wie String. Die Definition der Aufzählung lautet wie folgt: public enum eResult {Right = 1, NoncontrolledError = 2,}
Javiere
9
Übrigens können Sie in C # nicht mit dem Index itemNames [i] auf Array zugreifen, sondern nur mit arrayObject.GetValue (i). Auf diese Weise wird in beiden Fällen nur der Name zurückgegeben.
Javiere
1
Ich habe es gelöst, indem ich diese Lösung mit diesem Stapel
gemischt habe.
5
Warum hat das so viele positive Stimmen? Der Code (mindestens c #) funktioniert jetzt und enthält Syntaxfehler.
Dave
69

Verwenden Sie die folgende Dienstprogrammklasse Enumeration, um ein IDictionary<int,string>(Enum-Wert- und Namenspaar) aus einer Aufzählung abzurufen . Anschließend binden Sie das IDictionary an ein bindbares Steuerelement .

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

Beispiel: Verwenden der Utility-Klasse zum Binden von Aufzählungsdaten an ein Steuerelement

ddlResponse.DataSource = Enumeration.GetAll<Response>();
ddlResponse.DataTextField = "Value";
ddlResponse.DataValueField = "Key";
ddlResponse.DataBind();
Leyu
quelle
1
+1. Ich habe es benutzt, aber ich denke, der Schlüssel und der Wert sind falsch herum. Dies sollte ein IDictionary <string, int>
Colin
Es ist zu beachten, dass sich dies nicht bei allen Aufzählungstypen (wie uint, ulong, long usw.) korrekt verhält. Normalerweise ist der Schlüssel das effizienteste Suchfeld. In diesem Fall wäre dies das int, da Ganzzahlen ein einfacher <, =,> Vergleich mit dem <und> Vergleich eines Strings für jedes Zeichen sind.
Trisped
43

Ich benutze dies für 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() }))
Feryt
quelle
36

Meine Version ist nur eine komprimierte Form der oben genannten:

foreach (Response r in Enum.GetValues(typeof(Response)))
{
    ListItem item = new ListItem(Enum.GetName(typeof(Response), r), r.ToString());
    DropDownList1.Items.Add(item);
}
VanOrman
quelle
4
sollte sein (int r in Enum.GetValues ​​(typeof (Response))) oder es wird nur die Beschreibung als Name und Wert binden ...
Evan
2
Dies funktioniert nicht, da der Name des Aufzählungselements in den Wert von ListItem eingefügt wird. Die Konvertierung in int würde in den meisten Fällen funktionieren, jedoch nicht, wenn die Aufzählung uint, ulong oder long ist.
Trisped
Viel bessere Lösung IMHO.
Vippy
23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Jeder Enum-Typ leitet sich von System.Enum ab. Es gibt zwei statische Methoden, mit denen Daten an ein Dropdown-Listensteuerelement gebunden werden können (und der Wert abgerufen werden kann). Dies sind Enum.GetNames und Enum.Parse. Mit GetNames können Sie wie folgt an Ihr Dropdown-Listensteuerelement binden:

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

Nun, wenn Sie den Enum-Wert wieder bei Auswahl haben möchten ...

  private void ddColor_SelectedIndexChanged(object sender, System.EventArgs e)
  {
    Color selectedColor = (Color)Enum.Parse(typeof(Color),ddColor.SelectedValue
  }
p.campbell
quelle
2
gute Antwort, aber ein kleiner Tipp: Color selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);
sma6871
11

Nachdem ich alle Beiträge gelesen hatte, entwickelte ich eine umfassende Lösung, um das Anzeigen der Enum-Beschreibung in der Dropdown-Liste sowie das Auswählen des richtigen Werts aus dem Modell in der Dropdown-Liste bei der Anzeige im Bearbeitungsmodus zu unterstützen:

Aufzählung:

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

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

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

Enum-Erweiterungsklasse:

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

Modellklasse:

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

und Ansicht:

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

Wenn Sie dieses Dropdown-Menü ohne Bindung an Model verwenden, können Sie stattdessen Folgendes verwenden:

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

Auf diese Weise können Sie erwarten, dass in Ihrem Dropdown-Menü Beschreibung anstelle von Aufzählungswerten angezeigt wird. Auch beim Bearbeiten wird Ihr Modell nach der Buchungsseite durch einen Dropdown-Wert aktualisiert.

Amir Chatrbahr
quelle
1
Schön gemacht, besonders das bisschen mit den [Description] Annotationen. Ich werde diese Technik übernehmen.
Baxter
Ordentliche und saubere Erklärung. Kudos Amir !!
8

Wie andere bereits gesagt haben - binden Sie keine Daten an eine Aufzählung, es sei denn, Sie müssen je nach Situation an unterschiedliche Aufzählungen binden. Es gibt verschiedene Möglichkeiten, dies zu tun, einige Beispiele unten.

ObjectDataSource

Eine deklarative Methode mit ObjectDataSource. Erstellen Sie zunächst eine BusinessObject-Klasse, die die Liste zurückgibt, um die DropDownList an Folgendes zu binden:

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

Fügen Sie dann der ASPX-Seite ein HTML-Markup hinzu, um auf diese BO-Klasse zu verweisen:

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

Diese Option erfordert keinen Code dahinter.

Code hinter DataBind

So minimieren Sie den HTML-Code auf der ASPX-Seite und binden Code Behind ein:

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

Wie auch immer, der Trick besteht darin, die Enum-Methoden von GetValues, GetNames usw. für Sie arbeiten zu lassen.

Johan Danforth
quelle
6

Ich bin nicht sicher, wie ich es in ASP.NET machen soll, aber schau dir diesen Beitrag an ... könnte es helfen?

Enum.GetValues(typeof(Response));
Rudigrobler
quelle
6

Sie könnten linq verwenden:

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();
KrishnaDhungana
quelle
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);
}
John Willemse
quelle
4
public enum Color
{
    RED,
    GREEN,
    BLUE
}

ddColor.DataSource = Enum.GetNames(typeof(Color));
ddColor.DataBind();
Sankalp Gurha
quelle
3

Generischer Code mit Antwort sechs.

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

}
Muhammed Qasim
quelle
3

Nachdem ich diese Antwort gefunden hatte, fand ich eine meiner Meinung nach bessere (zumindest elegantere) Möglichkeit, dies zu tun. Ich dachte, ich würde zurückkommen und sie hier teilen.

Page 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);
Ben Hughes
quelle
2

Dies ist wahrscheinlich eine alte Frage. Aber so habe ich meine gemacht.

Modell:

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
}

Dann in der Ansicht: So füllen Sie das Dropdown-Menü aus.

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

Dies sollte alles in Ihrer Aufzählungsliste füllen. Hoffe das hilft..

Marie McDonley
quelle
Dies funktioniert jedoch. Sie benötigen eine Erweiterungsklasse, wenn Sie Zeichenfolgenliterale mit Leerzeichen einfügen möchten.
1
Dies ist die beste Antwort. @Nikul, du brauchst keine Erweiterungsklasse. Sie müssen nur Anmerkungen verwenden. [Display(Name = "Option number one")] Option1,
Rooter
1

Warum nicht so verwenden, um jede listControle zu übergeben:


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();
        }
Und die Verwendung ist genauso einfach wie:

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

Mostafa
quelle
1

ASP.NET wurde inzwischen mit einigen weiteren Funktionen aktualisiert, und Sie können jetzt die integrierte Aufzählung zum Dropdown verwenden.

Wenn Sie die Enum selbst binden möchten, verwenden Sie Folgendes:

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

Wenn Sie an eine Antwortinstanz gebunden sind, verwenden Sie Folgendes:

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

Dies ist meine Lösung für das Bestellen einer Aufzählung und einer Datenbindung (Text und Wert) zum Dropdown mit 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()));
Diego Mendes
quelle
0

Wenn Sie eine benutzerfreundlichere Beschreibung in Ihrem Kombinationsfeld (oder einem anderen Steuerelement) haben möchten, können Sie das Attribut Beschreibung mit der folgenden Funktion verwenden:

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

Hier ist ein Beispiel für eine Aufzählung mit angewendeten Beschreibungsattributen:

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

Dann binden, um so zu kontrollieren ...

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

Auf diese Weise können Sie beliebigen Text in die Dropdown-Liste einfügen, ohne dass er wie ein Variablenname aussehen muss

Josh Stribling
quelle
0

Sie können auch Erweiterungsmethoden verwenden. Für diejenigen , die nicht vertraut mit den Erweiterungen schlage ich vor, die Überprüfung VB und C # Dokumentation.


VB-Erweiterung:

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

So verwenden Sie die Erweiterung:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

C # -Erweiterung:

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

So verwenden Sie die Erweiterung:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Wenn Sie das ausgewählte Element gleichzeitig einstellen möchten, ersetzen Sie es

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

mit

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)

Durch die Konvertierung in System.Enum werden Probleme mit der Größe und der Ausgabe vermieden. Zum Beispiel wäre 0xFFFF0000 4294901760 als Uint, aber -65536 als Int.

TryCast und as System.Enum sind etwas schneller als Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 in meinen Geschwindigkeitstests).

Trisped
quelle
0

Die akzeptierte Lösung funktioniert nicht, aber der folgende Code hilft anderen bei der Suche nach der kürzesten Lösung.

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

Sie können dies viel kürzer tun

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