Как связать Enum с элементом управления DropDownList в ASP.NET?

Скажем, у меня есть следующее простое перечисление:

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

Как я могу привязать это перечисление к элементу управления DropDownList, чтобы описания отображались в списке, а также извлекали соответствующее числовое значение (1,2,3) после выбора параметра?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
128
0
172 721
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

Ответ принят как подходящий

Я, вероятно, не стал бы связывать данных, поскольку это перечисление, и оно не изменится после времени компиляции (если только у меня не будет одного из тех моментов сутулый).

Лучше просто перебрать перечисление:

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

Большое спасибо за этот ответ. GetType (Response) у меня не сработал, потому что я получил экземпляр Enum, а не класс Enum. Поэтому вместо этого я использую enumInstance.GetType ().

Sebastian 28.04.2010 19:07

Используя C#, у меня это не работает, потому что и getValues, и getNames возвращают одно и то же, первый как объекты, а второй как строка. Определение перечисления выглядит так: public enum eResult {Right = 1, NoncontrolledError = 2,}

Javiere 26.06.2013 15:27

Кстати, в C# вы не можете получить доступ к Array с индексом itemNames [i], вы можете сделать это только с arrayObject.GetValue (i), и таким образом он возвращает только имя в обоих случаях.

Javiere 26.06.2013 15:43

Я решил смешать это решение с этим stackoverflow.com/questions/3213432/…

Javiere 26.06.2013 16:12

itemValues ​​(i) вернет объект, если вам нужно значение, вы всегда можете выполнить Convert.ToInt32 (itemValues ​​(i)), который даст вам целое число

RdPC 27.02.2014 14:08

Если вам нужны эти значения: Выберите вариант: Да, Нет, Может быть с Select an option в качестве первого значения? Для использования значений Enum в фильтре (поиск) и значение необязательный для поиска. Если выбрано Выберите вариант, не применять значение перечисления к поиску.

Kiquenet 22.02.2016 10:25

Почему так много положительных отзывов. Код (по крайней мере, C#) теперь работает и содержит синтаксические ошибки.

Dave 04.10.2016 00:53

Это не совсем то, что вы ищете, но может помочь:

http://blog.jeffhandley.com/archive/2008/01/27/enum-list-dropdown-control.aspx

Я не уверен, как это сделать в ASP.NET, но посмотрите сообщение это ... это может помочь?

Enum.GetValues(typeof(Response));

Используйте следующий служебный класс Enumeration, чтобы получить IDictionary<int,string> (пара значений Enum и имени) из Перечисление; затем вы привязываете IDictionary к привязываемому Control.

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. Я использовал его, но я думаю, что ключ и значение ошибочны. Это должно вернуть IDictionary <string, int>

Colin 25.08.2011 20:42

Следует отметить, что это не будет вести себя правильно для всех типов перечислений (например, uint, ulong, long и т. д.). Обычно наиболее эффективным полем для поиска является ключ. В этом случае это будет int, поскольку целые числа представляют собой простое сравнение <, =,> и сравнение строк <и> для каждого символа.

Trisped 29.03.2012 03:50

Как уже говорили другие - не привязывайте данные к перечислению, если вам не нужно привязываться к разным перечислениям в зависимости от ситуации. Есть несколько способов сделать это, пара примеров ниже.

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 и т. д. Работать за вас.

Моя версия - это просто сжатая форма приведенного выше:

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

должен быть (int r в Enum.GetValues ​​(typeof (Response))) или просто привяжет описание как имя и значение ...

Evan 11.03.2010 03:29

это не работает, поскольку оно вставляет имя члена перечисления в значение ListItem. Преобразование в int будет работать в большинстве случаев, но не в том случае, если перечисление имеет тип uint, ulong или long.

Trisped 29.03.2012 03:53

Намного лучшее решение ИМХО.

Vippy 14.06.2016 22:41

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
  }

хороший ответ, но небольшой совет: Color selectedColor = (Color) Enum.Parse (typeof (Color), ddColor.SelectedValue);

sma6871 30.05.2015 11:34

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

Почему бы не использовать это, чтобы передать каждый 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();
        }
And use is just as simple as :

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

Общий код с использованием ответа шесть.

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

}

Я использую это для 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() }))

Найдя этот ответ, я придумал, что я считаю лучшим (по крайней мере, более элегантным) способом сделать это, подумал, что вернусь и поделюсь им здесь.

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

Это мое решение для заказа 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()));

Учебник по asp.net и winforms с комбинированным списком и раскрывающимся списком: Как использовать Enum с Combobox в C# WinForms и Asp.Net

надежда помогает

public enum Color
{
    RED,
    GREEN,
    BLUE
}

ddColor.DataSource = Enum.GetNames(typeof(Color));
ddColor.DataBind();

Ознакомьтесь с моим сообщением о создании специального помощника «ASP.NET MVC - Создание помощника DropDownList для перечислений»: http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx

Если вы хотите иметь более понятное описание в поле со списком (или другом элементе управления), вы можете использовать атрибут Description со следующей функцией:

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

Вот пример перечисления с примененными атрибутами 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";

Таким образом, вы можете поместить любой текст в раскрывающийся список без необходимости выглядеть как имя переменной.

Вы также можете использовать методы расширения. Для тех, кто не знаком с расширениями, я предлагаю проверить документацию 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 как uint, но будет -65536 как int.

TryCast и как System.Enum немного быстрее, чем Convert.ChangeType (enumTypeValues ​​[i], enumUnderType) .ToString () (12:13 в моих тестах скорости).

После прочтения всех сообщений я придумал комплексное решение для поддержки отображения описания перечисления в раскрывающемся списке, а также выбора правильного значения из модели в раскрывающемся списке при отображении в режиме редактирования:

перечисление:

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

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

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

класс расширения перечисления:

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

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

Красиво сделано, особенно бит с аннотациями [Описание]. Я буду применять эту технику.

Baxter 01.07.2015 22:18

Аккуратное и чистое объяснение. Престижность Амир !!

user2877627 21.05.2019 02:33

С тех пор ASP.NET был обновлен с некоторыми дополнительными функциями, и теперь вы можете использовать встроенное перечисление для раскрывающегося списка.

Если вы хотите привязать к самому Enum, используйте это:

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

Если вы привязываетесь к экземпляру Response, используйте это:

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

Вы можете использовать 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();

Принятое решение не работает, но приведенный ниже код поможет другим, ищущим кратчайшее решение.

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

Это, наверное, старый вопрос ... но я так и задал свой.

Модель:

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

Это должно заполнить все в вашем списке перечислений. Надеюсь это поможет..

Однако это работает, вам нужен класс расширения, если вы хотите включать строковые литералы с пробелами.

user2877627 21.05.2019 01:46

Это лучший ответ. @Nikul, тебе не нужен класс расширения. Вам нужно только использовать аннотации. [Display(Name = "Option number one")] Option1,

rooter 09.07.2019 20:28

Вы можете сделать это намного короче

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

Для тех из нас, кому нужно рабочее решение C#, которое работает с любым drop и enum ...

private void LoadConsciousnessDrop()
{
    string sel_val = this.drp_Consciousness.SelectedValue;
    this.drp_Consciousness.Items.Clear();
    string[] names = Enum.GetNames(typeof(Consciousness));
    
    for (int i = 0; i < names.Length; i++)
        this.drp_Consciousness.Items.Add(new ListItem(names[i], ((int)((Consciousness)Enum.Parse(typeof(Consciousness), names[i]))).ToString()));

    this.drp_Consciousness.SelectedValue = String.IsNullOrWhiteSpace(sel_val) ? null : sel_val;
}

Я понимаю, что этот пост старше и предназначен для Asp.net, но я хотел предоставить решение, которое я недавно использовал для проекта Windows Forms на C#. Идея состоит в том, чтобы создать словарь, в котором ключи - это имена перечислимых элементов, а значения - это перечисленные значения. Затем вы привязываете словарь к полю со списком. См. Универсальную функцию, которая принимает в качестве аргументов ComboBox и Enum Type.

    private void BuildComboBoxFromEnum(ComboBox box, Type enumType) {
        var dict = new Dictionary<string, int>();
        foreach (var foo in Enum.GetValues(enumType)) {
            dict.Add(foo.ToString(), (int)foo);
        }
        box.DropDownStyle = ComboBoxStyle.DropDownList; // Forces comboBox to ReadOnly
        box.DataSource = new BindingSource(dict, null);
        box.DisplayMember = "Key";
        box.ValueMember = "Value";
        // Register a callback that prints the Name and Value of the 
        // selected enum. This should be removed after initial testing.
        box.SelectedIndexChanged += (o, e) => {
            Console.WriteLine("{0} {1}", box.Text, box.SelectedValue);
        };
    }

Эту функцию можно использовать следующим образом:

BuildComboBoxFromEnum(comboBox1,typeof(Response));

Другие вопросы по теме