Як ви прив’язуєте Enum до елемента управління DropDownList в ASP.NET?


126

Скажімо, у мене є такий простий перерахунок:

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

Як я можу прив’язати цей перелік до елемента управління DropDownList, щоб описи відображалися у списку, а також отримували пов'язане числове значення (1,2,3), як тільки була обрана опція?

Відповіді:


112

Напевно, я б не пов'язував дані, оскільки це перерахунок, і вони не змінюватимуться після закінчення часу компіляції (якщо тільки у мене не буде одного з цих стопідних моментів).

Краще просто перебрати через перелік:

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

Або те саме в 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
Дякую за цю відповідь. GetType (Response) не працював для мене, тому що я отримую екземпляр Enum, а не клас Enum. Тому я використовую замість enumInstance.GetType ().
Себастьян

2
Використовуючи C #, для мене це не працює, тому що і getValues, і getNames повертають однакові, перший як об'єкти, а другий як рядок. Визначення перерахунку виглядає так: public enum eResult {Право = 1, неконтрольованийError = 2,}
Javiere

9
До речі, в C # ви не можете отримати доступ до масиву з індексом itemNames [i], ви могли це зробити лише з arrayObject.GetValue (i), і таким чином він повертає лише ім'я в обох випадках.
Javiere

1
Я вирішив , що це рішення змішання з цим одним stackoverflow.com/questions/3213432 / ...
Javiere

5
Чому це так багато відгуків. Код (принаймні, c #) зараз працює і містить синтаксичні помилки.
Дейв

69

Використовуйте наступний клас утиліти, Enumerationщоб отримати IDictionary<int,string>(значення значення Enum і пара імен) з перерахунку ; потім ви прив’язуєте IDictionary до керованого елемента керування.

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

Приклад: Використання класу утиліти для прив’язки даних перерахування до елемента управління

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

1
+1. Я використовував це, але думаю, що ключ і значення - неправильний шлях. Це повинно повернути IDictionary <string, int>
Колін

Слід зазначити, що це неправильно поводиться з усіх типів перерахунків (наприклад, uint, ulong, long тощо). Як правило, ключовим є найефективніше поле пошуку. У цьому випадку це буде int, оскільки цілі числа - це просте <, =,> порівняння порівняння з рядком <і> для кожного символу.
Trisped

43

Я використовую це для 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

Моя версія - це лише стисла форма перерахованого вище:

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

4
повинен бути (int r в Enum.GetValues ​​(typeof (Response))), або він просто прив’яже опис як ім'я та значення ...
Еван

2
це не працює, оскільки він вставляє ім'я члена перерахунку у значення ListItem. Перетворення в int працювало б у більшості випадків, але не, якщо enum є утінкою, улонгою чи довгою.
Trisped

Набагато краще рішення ІМХО.
Vippy

23
public enum Color
{
    RED,
    GREEN,
    BLUE
}

Кожен тип Enum походить від System.Enum. Існують два статичні методи, які допомагають прив’язати дані до керування випадаючого списку (та отримати значення). Це Enum.GetNames та Enum.Parse. Використовуючи GetNames, ви можете прив’язати до керування випадаючого списку наступним чином:

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

Тепер, якщо ви хочете, щоб значення Enum повернулося до вибору ....

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

2
хороша відповідь, але невелика порада: Колір обранийColor = (Колір) Enum.Parse (typeof (Color), ddColor.SelectedValue);
sma6871

11

Прочитавши всі публікації, я придумав комплексне рішення для підтримки відображення опису переліку у спадному списку, а також вибору належного значення з Моделі у спадному меню при відображенні в режимі редагування:

перерахувати:

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

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

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

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

Клас моделі:

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

та Переглянути:

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

і якщо ви використовуєте це спадне меню без прив’язки до моделі, ви можете використовувати це замість цього:

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

Таким чином, ви можете очікувати, що випадаюче меню відображатиме Опис, а не значення перерахунків. Крім того, коли мова заходить про «Правка», ваша модель буде оновлена ​​випадаючим значенням після сторінки публікації.


1
Чудово виконано, особливо це стосується анотацій [Опис]. Я буду приймати цю техніку.
Бакстер

Акуратне та чисте пояснення. Кудос Амір !!

8

Як вже говорили інші - не зв'язуйте дані з перерахунком, якщо вам не потрібно прив'язуватися до різних переліків залежно від ситуації. Є кілька способів зробити це, кілька прикладів нижче.

ObjectDataSource

Декларативний спосіб зробити це за допомогою ObjectDataSource. Спочатку створіть клас BusinessObject, який поверне Список, щоб прив'язати 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;
    }
}

Потім додайте трохи розмітки HTML на сторінку ASPX, щоб вказати на цей клас 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>

Цей параметр не вимагає коду позаду.

Код за DataBind

Щоб мінімізувати HTML на сторінці ASPX та зробити прив'язку в коді позаду:

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

У будь-якому разі, хитрість полягає в тому, щоб дозволити методам типу Enum GetValues, GetNames тощо працювати для вас.


6

Я не впевнений, як це зробити в ASP.NET, але ознайомтеся з цією публікацією ... це може допомогти?

Enum.GetValues(typeof(Response));

6

Ви можете використовувати 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

Загальний код, використовуючи відповідь шість.

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

Знайшовши цю відповідь, я придумав те, що, на мою думку, є кращим (принаймні більш елегантним) способом цього, подумав, що я повернусь і поділюсь цим тут.

Сторінка_завантаження:

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

Вантажні цінності:

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

SaveValues:

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

2

Це, мабуть, давнє питання .. але ось як я зробив своє.

Модель:

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
}

Потім у Перегляді: ось як скористатися спалювальним меню.

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

Це має заповнити все у вашому переліку. Сподіваюся, це допомагає ..


Це працює, проте вам потрібен клас розширення, якщо ви хочете включити рядкові літерали з пробілами.

1
Це найкраща відповідь. @Nikul, вам не потрібен клас розширення. Потрібно використовувати лише примітки. [Display(Name = "Option number one")] Option1,
rooter


1

Чому б не скористатися таким, щоб можна було передати кожен список Контроль:


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();
        }
І використовувати так само просто, як:

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


1

З тих пір ASP.NET оновлювався ще деякими функціональними можливостями, і тепер ви можете використовувати вбудований перерахунок для спадання.

Якщо ви хочете прив’язати себе до Enum, скористайтеся цим:

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

Якщо ви прив'язуєте до екземпляра Response, використовуйте це:

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

0

Це моє рішення для замовлення спадного пакету Enum та DataBind (текст і значення) за допомогою 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

Якщо ви хочете, щоб у вашому комбінованому вікні (або іншому елементі управління) був більш зручний опис, ви можете скористатися атрибутом Опис за допомогою наступної функції:

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

Ось приклад enum із застосованими атрибутами Description:

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

Тоді зобов’язатись керувати так ...

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

Таким чином, ви можете помістити будь-який текст, який ви хочете, у спадному меню без того, щоб він був схожий на ім’я змінної


0

Ви також можете використовувати методи розширення. Для тих, хто не знайомий з розширеннями, пропоную перевірити документацію VB та C # .


Розширення 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

Щоб використовувати розширення:

Imports <projectName>.CustomExtensions.ListItemCollectionExtension

...

yourDropDownList.Items.AddEnum(Of EnumType)()

Розширення 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")));
            }
        }
    }
}

Щоб використовувати розширення:

using CustomExtensions.ListItemCollectionExtension;

...

yourDropDownList.Items.AddEnum<EnumType>()

Якщо ви хочете встановити вибраний елемент, одночасно замініть

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

з

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)

Шляхом перетворення на System.Enum, а не уникнення проблем з розміром і виведенням. Наприклад, 0xFFFF0000 буде 4294901760 як утінка, але буде -65536 як int.

TryCast і як System.Enum трохи швидше, ніж Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 у моїх тестах на швидкість).



0

Прийняте рішення не працює, але наведений нижче код допоможе іншим, хто шукає найкоротше рішення.

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

0

Ви можете зробити це набагато коротше

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);
            }
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.