Como você vincula um Enum a um controle DropDownList no ASP.NET?


126

Digamos que tenho a seguinte enumeração simples:

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

Como vincular essa enumeração a um controle DropDownList para que as descrições sejam exibidas na lista e recupere o valor numérico associado (1,2,3) depois que uma opção foi selecionada?

Respostas:


112

Provavelmente, eu não vincularia os dados, pois é um enum e não mudará após o tempo de compilação (a menos que eu esteja tendo um desses momentos estúpidos ).

Melhor apenas para percorrer a enum:

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 o mesmo em 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
Muito obrigado por esta resposta. GetType (Response) não funcionou para mim porque eu recebi uma instância da Enum, em vez da classe Enum. Então, eu uso enumInstance.GetType ().
28710 Sebastian

2
Usando C #, não está funcionando para mim, porque getValues ​​e getNames retornam o mesmo, o primeiro como objetos e a segunda como. A definição da enumeração é assim: eResult public enum {Direita = 1, NoncontrolledError = 2,}
Javiere

9
A propósito, em C #, você não pode acessar a Matriz com o índice itemNames [i], você só pode fazê-lo com arrayObject.GetValue (i) e, dessa forma, retorna apenas o nome nos dois casos.
Javiere

1
Eu resolvi misturar esta solução com um presente stackoverflow.com/questions/3213432/...
Javiere

5
Por que isso tem tantos votos positivos? O código (pelo menos c #) agora funciona e contém erros de sintaxe.
Dave

69

Use a seguinte classe de utilitário Enumerationpara obter um IDictionary<int,string>(par de valor e nome da enumeração ) de uma enumeração ; você vincula o IDictionary a um controle vinculável.

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

Exemplo: Usando a Classe Utilitária para Ligar Dados de Enumeração a um Controle

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

1
+1. Eu usei, mas acho que a chave e o valor estão ao contrário. Isso deve retornar um IDictionary <string, int>
Colin

Deve-se observar que isso não se comportará corretamente de todos os tipos de enumerações (como uint, ulong, long etc.). Normalmente, o campo mais eficiente para pesquisar é a chave. Nesse caso, o que seria o int, pois os números inteiros são uma comparação simples <, =,> versus a comparação <e> de uma string para cada caractere.
Trisped

43

Eu uso isso para o 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

Minha versão é apenas uma forma compactada do acima:

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

4
deve ser (int r em Enum.GetValues ​​(typeof (Response))) ou apenas vinculará a descrição como o nome e o valor ...
Evan

2
isso não funciona, pois insere o nome do membro da enumeração no valor do ListItem. A conversão para int funcionaria na maioria dos casos, mas não se o enum for um uint, ulong ou longo.
Trisped

Solução muito melhor IMHO.
Vippy

23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Todo tipo de Enum deriva de System.Enum. Existem dois métodos estáticos que ajudam a vincular dados a um controle de lista suspensa (e recuperar o valor). Estes são Enum.GetNames e Enum.Parse. Usando GetNames, você pode vincular ao seu controle da lista suspensa da seguinte maneira:

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

Agora, se você deseja o valor Enum Voltar à seleção ....

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

2
boa resposta, mas com uma pequena dica: Cor selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);
Sma6871

11

Depois de ler todas as postagens, criei uma solução abrangente para oferecer suporte à exibição da descrição de enum na lista suspensa, bem como à seleção do valor adequado do modelo na lista suspensa ao exibir no modo de edição:

enum:

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

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

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

classe de extensão 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 modelo:

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

e Ver:

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

e se você estiver usando esse menu suspenso sem vincular ao Model, poderá usar isso:

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

Assim, você pode esperar que seu menu suspenso exiba Descrição em vez de valores de enumeração. Além disso, quando se trata de Editar, seu modelo será atualizado pelo valor selecionado suspenso após a postagem da página.


1
Muito bem feito, especialmente o pouco com as anotações [Descrição]. Eu vou adotar essa técnica.
Baxter

Explicação pura e limpa. Kudos Amir !!

8

Como outros já disseram - não vincule a uma enumeração, a menos que precise vincular a enumerações diferentes, dependendo da situação. Existem várias maneiras de fazer isso, alguns exemplos abaixo.

ObjectDataSource

Uma maneira declarativa de fazê-lo com ObjectDataSource. Primeiro, crie uma classe BusinessObject que retornará a lista para vincular o 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;
    }
}

Em seguida, adicione alguma marcação HTML à página ASPX para apontar para esta 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>

Esta opção não requer código por trás.

Código por trás do DataBind

Para minimizar o HTML na página ASPX e vincular no 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()));
        }
    }
}

De qualquer forma, o truque é deixar os métodos do tipo Enum de GetValues, GetNames etc. trabalharem para você.


6

Não sei como fazê-lo no ASP.NET, mas confira este post ... ele pode ajudar?

Enum.GetValues(typeof(Response));

6

Você poderia usar o 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

Código genérico usando a resposta seis.

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

Depois de encontrar essa resposta, criei uma maneira melhor (pelo menos mais elegante) de fazer isso, pensei em voltar e compartilhá-la aqui.

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

2

Esta é provavelmente uma pergunta antiga ... mas foi assim que fiz a minha.

Modelo:

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
}

Em seguida, no modo de exibição: veja como usar preencher o menu suspenso.

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

Isso deve preencher tudo na sua lista de enumerações. Espero que isto ajude..


Isso funciona, no entanto, você precisa de uma classe de extensão se desejar incorporar literais de seqüência de caracteres com espaços.

1
Esta é a melhor resposta. @ Nikul, você não precisa de uma classe de extensão. Você só precisa usar anotações. [Display(Name = "Option number one")] Option1,
rooter


1

Por que não usar dessa maneira para poder passar todos os 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 o uso é tão simples quanto:

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


1

Desde então, o ASP.NET foi atualizado com um pouco mais de funcionalidade e agora você pode usar a enumeração interna para a lista suspensa.

Se você deseja vincular o próprio Enum, use este:

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

Se você estiver vinculando uma instância do Response, use o seguinte:

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

0

Esta é a minha solução para solicitar um enum e DataBind (texto e valor) para o menu suspenso usando 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 você quiser ter uma descrição mais amigável na sua caixa de combinação (ou outro controle), poderá usar o atributo Descrição com a seguinte função:

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

Aqui está um exemplo de uma enumeração com os atributos Descrição aplicados:

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

Então ligue para controlar assim ...

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

Dessa forma, você pode colocar o texto que quiser na lista suspensa, sem que seja necessário o nome de uma variável


0

Você também pode usar métodos de extensão. Para aqueles que não estão familiarizados com extensões, sugiro verificar a documentação do VB e C # .


Extensão 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

Para usar a extensão:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

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

Para usar a extensão:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Se você deseja definir o item selecionado ao mesmo tempo, substitua

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

com

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)

Ao converter para System.Enum, são evitados os problemas de tamanho e saída int. Por exemplo, 0xFFFF0000 seria 4294901760 como um uint, mas seria -65536 como um int.

TryCast e como System.Enum são um pouco mais rápidos que Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 nos meus testes de velocidade).



0

A solução aceita não funciona, mas o código abaixo ajudará outras pessoas a procurar a solução mais curta.

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

0

Você pode fazer isso muito mais curto

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);
            }
        }
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.