Comment liez-vous un Enum à un contrôle DropDownList dans ASP.NET?

126

Disons que j'ai l'énumération simple suivante:

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

Comment puis-je lier cette énumération à un contrôle DropDownList afin que les descriptions s'affichent dans la liste et récupérer la valeur numérique associée (1, 2, 3) une fois qu'une option a été sélectionnée?

Rayon
la source

Réponses:

112

Je ne lierais probablement pas les données car il s'agit d'une énumération, et cela ne changera pas après la compilation (à moins que je ne connaisse un de ces moments stoopid ).

Mieux vaut simplement parcourir l'énumération:

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

Ou la même chose en 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
la source
1
Merci beaucoup pour cette réponse. GetType (Response) n'a pas fonctionné pour moi car je reçois une instance de Enum, plutôt que la classe Enum. J'utilise donc enumInstance.GetType () à la place.
Sebastian
2
En utilisant C #, cela ne fonctionne pas pour moi, car getValues ​​et getNames renvoient la même chose, le premier comme des objets et le second comme une chaîne. La définition de l'énumération est la suivante: public enum eResult {Right = 1, NoncontrolledError = 2,}
Javiere
9
D'ailleurs en C #, vous ne pouvez pas accéder à Array avec l'index itemNames [i], vous ne pouvez le faire qu'avec arrayObject.GetValue (i) et de cette façon, il renvoie juste le nom dans les deux cas.
Javiere
1
Je l'ai résolu en mélangeant cette solution avec celle-ci stackoverflow.com/questions/3213432/…
Javiere
5
Pourquoi cela a-t-il autant de votes positifs? Le code (au moins c #) fonctionne maintenant et contient des erreurs de syntaxe.
Dave
69

Utilisez la classe d'utilitaire suivante Enumerationpour obtenir une IDictionary<int,string>(paire valeur et nom d' énumération ) à partir d'une énumération ; vous liez ensuite l' IDictionary à un contrôle pouvant être lié.

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

Exemple: utilisation de la classe utilitaire pour lier les données d'énumération à un contrôle

ddlResponse.DataSource = Enumeration.GetAll<Response>();
ddlResponse.DataTextField = "Value";
ddlResponse.DataValueField = "Key";
ddlResponse.DataBind();
Leyu
la source
1
+1. Je l'ai utilisé, mais je pense que la clé et la valeur sont dans le mauvais sens. Cela devrait renvoyer un IDictionary <string, int>
Colin
Il convient de noter que cela ne se comportera pas correctement de tous les types d'énumérations (comme uint, ulong, long, etc.) Normalement, le champ le plus efficace à rechercher est la clé. Dans ce cas, ce serait le entier puisque les entiers sont une simple comparaison <, =,> par rapport à une comparaison <et> d'une chaîne pour chaque caractère.
Trisped
43

J'utilise ceci pour 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
la source
36

Ma version est juste une forme compressée de ce qui précède:

foreach (Response r in Enum.GetValues(typeof(Response)))
{
    ListItem item = new ListItem(Enum.GetName(typeof(Response), r), r.ToString());
    DropDownList1.Items.Add(item);
}
VanOrman
la source
4
devrait être (int r dans Enum.GetValues ​​(typeof (Response))) ou il va simplement lier la description comme le nom et la valeur ...
Evan
2
cela ne fonctionne pas, car il insère le nom du membre de l'énumération dans la valeur de ListItem. La conversion en int fonctionnerait dans la plupart des cas, mais pas si l'énumération est un uint, ulong ou long.
Trisped
Une bien meilleure solution à mon humble avis.
Vippy le
23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Chaque type Enum dérive de System.Enum. Il existe deux méthodes statiques qui permettent de lier les données à un contrôle de liste déroulante (et de récupérer la valeur). Ce sont Enum.GetNames et Enum.Parse. À l'aide de GetNames, vous pouvez vous lier à votre contrôle de liste déroulante comme suit:

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

Maintenant, si vous voulez que la valeur Enum revienne sur la sélection ...

  private void ddColor_SelectedIndexChanged(object sender, System.EventArgs e)
  {
    Color selectedColor = (Color)Enum.Parse(typeof(Color),ddColor.SelectedValue
  }
p.campbell
la source
2
bonne réponse mais un petit conseil: Color selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);
sma6871
11

Après avoir lu tous les articles, j'ai proposé une solution complète pour prendre en charge l'affichage de la description de l'énumération dans la liste déroulante ainsi que la sélection de la valeur appropriée dans le modèle dans la liste déroulante lors de l'affichage en mode d'édition:

énumération:

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

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

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

classe d'extension 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 de modèle:

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

et voir:

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

et si vous utilisez cette liste déroulante sans liaison avec Model, vous pouvez l'utiliser à la place:

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

Ainsi, vous pouvez vous attendre à ce que votre liste déroulante affiche Description au lieu des valeurs d'énumération. En ce qui concerne également la modification, votre modèle sera mis à jour par la valeur sélectionnée dans le menu déroulant après la publication de la page.

Amir Chatrbahr
la source
1
Bien fait, surtout le bit avec les annotations [Description]. J'adopterai cette technique.
Baxter
Explication soignée et propre. Félicitations Amir !!
8

Comme d'autres l'ont déjà dit, ne reliez pas de données à une énumération, sauf si vous devez vous lier à différentes énumérations en fonction de la situation. Il existe plusieurs façons de procéder, quelques exemples ci-dessous.

ObjectDataSource

Une manière déclarative de le faire avec ObjectDataSource. Tout d'abord, créez une classe BusinessObject qui renverra la liste pour lier la DropDownList à:

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

Ajoutez ensuite un balisage HTML à la page ASPX pour pointer vers cette 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>

Cette option ne nécessite aucun code derrière.

Code derrière DataBind

Pour réduire le HTML dans la page ASPX et effectuer la liaison dans 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()));
        }
    }
}

Quoi qu'il en soit, l'astuce est de laisser les méthodes de type Enum de GetValues, GetNames etc. travailler pour vous.

Johan Danforth
la source
6

Je ne sais pas comment le faire dans ASP.NET mais consultez cet article ... cela pourrait aider?

Enum.GetValues(typeof(Response));
Rudigrobler
la source
6

Vous pouvez utiliser 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();
KrishnaDhungana
la source
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
la source
4
public enum Color
{
    RED,
    GREEN,
    BLUE
}

ddColor.DataSource = Enum.GetNames(typeof(Color));
ddColor.DataBind();
sankalp gurha
la source
3

Code générique utilisant la réponse six.

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
la source
3

Après avoir trouvé cette réponse, j'ai trouvé ce que je pense être une meilleure façon (au moins plus élégante) de faire cela, j'ai pensé que je reviendrais et la partagerais ici.

Page Load:

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

LoadValues:

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

Enregistrer les valeurs:

Response rOut = (Response) Enum.Parse(typeof(Response), DropDownList1.Text);
Ben Hughes
la source
2

C'est probablement une vieille question ... mais c'est comme ça que j'ai fait la mienne.

Modèle:

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
}

Ensuite, dans la vue: voici comment utiliser remplir la liste déroulante.

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

Cela devrait remplir tout dans votre liste d'énumération. J'espère que cela t'aides..

Marie McDonley
la source
Cela fonctionne cependant, vous avez besoin d'une classe d'extension si vous souhaitez incorporer des chaînes littérales avec des espaces.
1
C'est la meilleure réponse. @Nikul, vous n'avez pas besoin d'une classe d'extension. Il vous suffit d'utiliser des annotations. [Display(Name = "Option number one")] Option1,
rooter le
1

Pourquoi ne pas utiliser comme ça pour pouvoir passer chaque 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();
        }
Et l'utilisation est aussi simple que:

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

Mostafa
la source
1

ASP.NET a depuis été mis à jour avec des fonctionnalités supplémentaires et vous pouvez désormais utiliser l'énumération intégrée pour la liste déroulante.

Si vous souhaitez créer une liaison sur Enum lui-même, utilisez ceci:

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

Si vous liez une instance de Response, utilisez ceci:

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

C'est ma solution pour Order an Enum et DataBind (Text and Value) to Dropdown en utilisant 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
la source
0

Si vous souhaitez avoir une description plus conviviale dans votre zone de liste déroulante (ou autre contrôle), vous pouvez utiliser l'attribut Description avec la fonction suivante:

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

Voici un exemple d'énumération avec les attributs Description appliqués:

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

Puis Bind pour contrôler comme ça ...

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

De cette façon, vous pouvez mettre le texte de votre choix dans la liste déroulante sans qu'il ait à ressembler à un nom de variable

Josh Stribling
la source
0

Vous pouvez également utiliser des méthodes d'extension. Pour ceux qui ne sont pas familiers avec les extensions, je suggère de vérifier la documentation VB et C # .


Extension 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

Pour utiliser l'extension:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

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

Pour utiliser l'extension:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Si vous souhaitez définir l'élément sélectionné en même temps, remplacez

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

avec

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)

En convertissant en System.Enum plutôt qu'en taille int et les problèmes de sortie sont évités. Par exemple, 0xFFFF0000 serait 4294901760 comme uint mais serait -65536 comme int.

TryCast et as System.Enum sont légèrement plus rapides que Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 dans mes tests de vitesse).

Trisped
la source
0

La solution acceptée ne fonctionne pas, mais le code ci-dessous aidera les autres à rechercher la solution la plus courte.

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

Vous pouvez le faire beaucoup plus court

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