繁体   English   中英

如何将 Enum 绑定到 ASP.NET 中的 DropDownList 控件?

[英]How do you bind an Enum to a DropDownList control in ASP.NET?

假设我有以下简单的枚举:

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

如何将此枚举绑定到 DropDownList 控件,以便在列表中显示描述以及在选择选项后检索关联的数值 (1,2,3)?

我可能不会绑定数据,因为它是一个枚举,并且在编译后它不会改变(除非我有一个愚蠢的时刻)。

最好只遍历枚举:

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

使用以下实用程序 class EnumerationEnumeration获取IDictionary<int,string> (枚举值和名称对); 然后将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;
    }
}

示例:使用实用程序 class 将枚举数据绑定到控件

ddlResponse.DataSource = Enumeration.GetAll<Response>();
ddlResponse.DataTextField = "Value";
ddlResponse.DataValueField = "Key";
ddlResponse.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() }))

我的版本只是上述的压缩形式:

foreach (Response r in Enum.GetValues(typeof(Response)))
{
    ListItem item = new ListItem(Enum.GetName(typeof(Response), r), r.ToString());
    DropDownList1.Items.Add(item);
}
public enum Color
{
    RED,
    GREEN,
    BLUE
}

每个 Enum 类型都派生自 System.Enum。 有两种 static 方法可帮助将数据绑定到下拉列表控件(并检索值)。 它们是 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 值 Back on Selection....

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

在阅读了所有帖子后,我想出了一个全面的解决方案,以支持在下拉列表中显示枚举描述以及在编辑模式下显示时从下拉列表中的 Model 中选择适当的值:

枚举:

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

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

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

枚举扩展 class:

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

Model class:

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

和查看:

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

如果您使用该下拉列表而不绑定到 Model,则可以改用它:

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

因此,通过这样做,您可以期望您的下拉列表显示描述而不是枚举值。 此外,在编辑方面,您的 model 将在发布页面后通过下拉选择的值进行更新。

正如其他人已经说过的那样 - 不要将数据绑定到枚举,除非您需要根据情况绑定到不同的枚举。 有几种方法可以做到这一点,下面是几个例子。

对象数据源

使用 ObjectDataSource 的声明方式。 首先,创建一个 BusinessObject class,它将返回 List 以将 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 class:

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

此选项不需要后面的代码。

数据绑定背后的代码

要最小化 ASPX 页面中的 HTML 并在代码隐藏中进行绑定:

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

无论如何,诀窍是让 GetValues、GetNames 等 Enum 类型的方法为您工作。

您可以使用 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();

我不确定如何在 ASP.NET 中做到这一点,但请查看这篇文章......它可能会有所帮助吗?

Enum.GetValues(typeof(Response));
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);
}
public enum Color
{
    RED,
    GREEN,
    BLUE
}

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

使用答案六的通用代码。

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

}

找到这个答案后,我想出了我认为更好(至少更优雅)的方法,我想我会回来在这里分享。

页面加载:

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

加载值:

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

保存值:

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

这可能是一个老问题..但这就是我的做法。

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
}

然后在视图中:这里是如何使用填充下拉列表。

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

这应该填充枚举列表中的所有内容。 希望这可以帮助..

为什么不使用这样的方式来传递每个 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();
        }
使用很简单:
 BindToEnum(typeof(NewsType), DropDownList1); BindToEnum(typeof(NewsType), CheckBoxList1); BindToEnum(typeof(NewsType), RadoBuuttonList1);

ASP.NET 已经更新了更多功能,您现在可以使用内置枚举来下拉菜单。

如果要绑定 Enum 本身,请使用以下命令:

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

如果您要绑定 Response 的实例,请使用以下命令:

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

这不是您要寻找的,但可能会有所帮助:

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

接受的解决方案不起作用,但下面的代码将帮助其他人寻找最短的解决方案。

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

这是我使用 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()));

Both asp.net and winforms tutorial with combobox and dropdownlist: How to use Enum with Combobox in C# WinForms and Asp.Net

希望有帮助

您可以更短地执行此操作

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

对于我们这些想要一个适用于任何 drop 和 enum 的有效 C# 解决方案的人......

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,但我想提供一个我最近用于 c# Windows Z6450246253191829AC6EZ 项目的解决方案。 这个想法是建立一个字典,其中键是枚举元素的名称,值是枚举值。 然后将字典绑定到 combobox。 请参阅通用 function,它采用 ComboBox 和枚举类型作为 arguments。

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

这个 function 可以按如下方式使用:

BuildComboBoxFromEnum(comboBox1,typeof(Response));

在 ASP.NET Core 中,您可以使用以下 Html 助手(来自 Microsoft.AspNetCore.Mvc.Rendering):

<select asp-items="Html.GetEnumSelectList<GridReportingStatusFilters>()">
     <option value=""></option>
</select>

查看我关于创建自定义帮助程序“ASP.NET MVC - 为枚举创建 DropDownList 帮助程序”的帖子:http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc -creating-a-dropdownlist-helper-for-enums.aspx

如果您想在组合框(或其他控件)中有更用户友好的描述,您可以使用带有以下 function 的描述属性:

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

这样,您可以在下拉列表中放置您想要的任何文本,而不必看起来像变量名

您还可以使用扩展方法。 对于那些不熟悉扩展的人,我建议查看VBC#文档。


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 而不是 int 大小,可以避免 output 问题。 例如,0xFFFF0000 作为 uint 将是 4294901760,但作为 int 将是 -65536。

TryCast 和 as System.Enum 比 Convert.ChangeType(enumTypeValues[i], enumUnderType).ToString() 稍快(在我的速度测试中为 12:13)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM