Bagaimana Anda mengikat Enum ke kontrol DropDownList di ASP.NET?

126

Katakanlah saya memiliki enum sederhana berikut:

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

Bagaimana cara mengikat enum ini ke kontrol DropDownList sehingga deskripsinya ditampilkan dalam daftar serta mengambil nilai numerik terkait (1,2,3) setelah opsi dipilih?

sinar
sumber

Jawaban:

112

Saya mungkin tidak akan mengikat data karena ini adalah enum, dan itu tidak akan berubah setelah waktu kompilasi (kecuali saya mengalami salah satu momen yang membosankan itu ).

Lebih baik hanya mengulang melalui 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

Atau sama di 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
sumber
1
Terima kasih banyak atas jawaban ini. GetType (Respon) tidak bekerja untuk saya karena saya menerima contoh Enum, bukan kelas Enum. Jadi saya menggunakan enumInstance.GetType () sebagai gantinya.
Sebastian
2
Menggunakan C #, itu tidak berfungsi untuk saya, karena getValues ​​dan getNames mengembalikan sama, objek like pertama dan string like kedua. Definisi enumnya seperti ini: public enum eResult {Right = 1, NoncontrolledError = 2,}
Javiere
9
Ngomong-ngomong di C #, Anda tidak dapat mengakses Array dengan indeks itemNames [i], Anda hanya bisa melakukannya dengan arrayObject.GetValue (i) dan dengan cara itu, hanya mengembalikan nama dalam kedua kasus.
Javiere
1
Saya menyelesaikannya dengan mencampur solusi ini dengan stackoverflow.com/questions/3213432/…
Javiere
5
Mengapa ini memiliki begitu banyak suara positif. Kode (setidaknya c #) sekarang berfungsi dan mengandung kesalahan sintaks.
Dave
69

Gunakan kelas utilitas berikut Enumerationuntuk mendapatkan IDictionary<int,string>(Pasangan nilai & nama) dari Enumerasi ; Anda kemudian mengikat IDictionary ke Kontrol yang dapat diikat.

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

Contoh: Menggunakan kelas utilitas untuk mengikat data pencacahan ke kontrol

ddlResponse.DataSource = Enumeration.GetAll<Response>();
ddlResponse.DataTextField = "Value";
ddlResponse.DataValueField = "Key";
ddlResponse.DataBind();
Leyu
sumber
1
+1. Saya telah menggunakannya, tetapi saya pikir kunci dan nilainya salah. Ini harus mengembalikan IDictionary <string, int>
Colin
Perlu dicatat bahwa ini tidak akan berperilaku dengan benar untuk semua jenis enum (seperti uint, ulong, long, dll.) Biasanya bidang yang paling efisien untuk pencarian adalah kuncinya. Dalam hal ini yang akan menjadi int karena integer adalah perbandingan <, =,> sederhana vs perbandingan <dan> string untuk setiap karakter.
Dilanggar
43

Saya menggunakan ini untuk 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
sumber
36

Versi saya hanyalah bentuk terkompresi di atas:

foreach (Response r in Enum.GetValues(typeof(Response)))
{
    ListItem item = new ListItem(Enum.GetName(typeof(Response), r), r.ToString());
    DropDownList1.Items.Add(item);
}
VanOrman
sumber
4
harus (int r di Enum.GetValues ​​(typeof (Response))) atau hanya akan mengikat deskripsi sebagai nama dan nilainya ...
Evan
2
ini tidak bekerja, karena memasukkan nama anggota enumerasi dalam nilai ListItem. Mengonversi ke int akan berhasil dalam banyak kasus, tetapi tidak jika enum adalah uint, ulong, atau panjang.
Dicoret
Solusi yang jauh lebih baik IMHO.
Vippy
23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Setiap jenis Enum berasal dari System.Enum. Ada dua metode statis yang membantu mengikat data ke kontrol daftar drop-down (dan mengambil nilainya). Ini adalah Enum.GetNames dan Enum.Parse. Menggunakan GetNames, Anda dapat mengikat kontrol daftar drop-down Anda sebagai berikut:

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

Sekarang jika Anda menginginkan nilai Enum Back on Selection ....

  private void ddColor_SelectedIndexChanged(object sender, System.EventArgs e)
  {
    Color selectedColor = (Color)Enum.Parse(typeof(Color),ddColor.SelectedValue
  }
p. campbell
sumber
2
jawaban yang bagus tapi sedikit tip: Color selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);
sma6871
11

Setelah membaca semua posting saya menemukan solusi komprehensif untuk mendukung menampilkan deskripsi enum dalam daftar dropdown serta memilih nilai yang tepat dari Model di dropdown saat menampilkan dalam mode Edit:

enum:

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

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

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

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

Kelas model:

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

dan Lihat:

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

dan jika Anda menggunakan tarik-turun itu tanpa terikat ke Model, Anda dapat menggunakan ini sebagai gantinya:

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

Jadi dengan melakukan itu Anda dapat mengharapkan dropdown Anda menampilkan Description, bukan nilai enum. Juga ketika datang ke Edit, model Anda akan diperbarui dengan nilai dropdown yang dipilih setelah halaman posting.

Amir Chatrbahr
sumber
1
Bagus sekali, terutama bagian kecilnya dengan anotasi [Description]. Saya akan mengadopsi teknik ini.
Baxter
Penjelasan Rapi & Bersih. Kudos Amir !!
8

Seperti yang telah dikatakan orang lain - jangan mengikat data ke enum, kecuali Anda perlu mengikat ke enum yang berbeda tergantung pada situasinya. Ada beberapa cara untuk melakukannya, beberapa contoh di bawah.

ObjectDataSource

Cara deklaratif untuk melakukannya dengan ObjectDataSource. Pertama, buat kelas BusinessObject yang akan mengembalikan Daftar untuk mengikat DropDownList ke:

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

Kemudian tambahkan beberapa markup HTML ke halaman ASPX untuk mengarah ke kelas BO ini:

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

Opsi ini tidak memerlukan kode di belakang.

Kode Dibalik DataBind

Untuk meminimalkan HTML di halaman ASPX dan mengikat di belakang kode:

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

Bagaimanapun, triknya adalah membiarkan metode tipe Enum dari GetValues, GetNames, dll. Bekerja untuk Anda.

Johan Danforth
sumber
6

Saya tidak yakin bagaimana melakukannya di ASP.NET tapi lihat posting ini ... mungkin bisa membantu?

Enum.GetValues(typeof(Response));
rudigrobler
sumber
6

Anda bisa menggunakan 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
sumber
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
sumber
4
public enum Color
{
    RED,
    GREEN,
    BLUE
}

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

Kode Generik Menggunakan Jawaban enam.

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

Setelah menemukan jawaban ini, saya menemukan cara yang menurut saya lebih baik (setidaknya lebih elegan) untuk melakukan ini, saya pikir saya akan kembali dan membagikannya di sini.

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

Ini mungkin pertanyaan lama .. tapi begitulah cara saya melakukannya.

Model:

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
}

Kemudian di View: inilah cara menggunakan populate dropdown.

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

Ini harus mengisi semua yang ada di daftar enum Anda. Semoga ini membantu..

Marie McDonley
sumber
Namun ini berfungsi, Anda memerlukan kelas ekstensi jika Anda ingin menggabungkan string literal dengan spasi.
1
Ini jawaban terbaik. @ Nikul, Anda tidak memerlukan kelas ekstensi. Anda hanya perlu menggunakan anotasi. [Display(Name = "Option number one")] Option1,
rooter
1

Mengapa tidak menggunakan seperti ini agar dapat meneruskan setiap 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();
        }
Dan penggunaannya sesederhana:

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

Mostafa
sumber
1

ASP.NET sejak itu telah diperbarui dengan beberapa fungsionalitas lagi, dan Anda sekarang dapat menggunakan enum bawaan untuk dropdown.

Jika Anda ingin mengikat Enum itu sendiri, gunakan ini:

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

Jika Anda mengikat sebuah instance dari Respon, gunakan ini:

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

Ini adalah solusi saya untuk Memesan Enum dan DataBind (Teks dan Nilai) ke Dropdown menggunakan 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
sumber
0

Jika Anda ingin memiliki deskripsi yang lebih ramah pengguna di kotak kombo Anda (atau kontrol lain), Anda dapat menggunakan atribut Description dengan fungsi berikut:

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

Berikut adalah contoh enum dengan atribut Description diterapkan:

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

Kemudian Bind untuk mengontrol seperti ini ...

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

Dengan cara ini Anda dapat meletakkan teks apa pun yang Anda inginkan di drop-down tanpa harus terlihat seperti nama variabel

Josh Stribling
sumber
0

Anda juga bisa menggunakan metode Ekstensi. Bagi mereka yang tidak terbiasa dengan ekstensi, saya sarankan untuk memeriksa dokumentasi VB dan C # .


Ekstensi 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

Untuk menggunakan ekstensi:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

C # Ekstensi:

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

Untuk menggunakan ekstensi:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Jika Anda ingin mengatur item yang dipilih sekaligus mengganti

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

dengan

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)

Dengan mengkonversi ke System.Enum daripada ukuran int dan masalah keluaran dihindari. Misalnya 0xFFFF0000 akan menjadi 4294901760 sebagai uint tetapi akan menjadi -65536 sebagai int.

TryCast dan System.Enum sedikit lebih cepat daripada Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 dalam tes kecepatan saya).

Dicoret
sumber
0

Solusi yang diterima tidak berfungsi, tetapi kode di bawah ini akan membantu orang lain mencari solusi terpendek.

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

Anda bisa melakukan ini jauh lebih singkat

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
sumber