关于C#:如何从ASP.NET MVC中的枚举创建DropDownList?

How do you create a dropdownlist from an enum in ASP.NET MVC?

我正在尝试使用Html.DropDownList扩展方法,但不知道如何将它与枚举一起使用。

假设我有这样一个枚举:

1
2
3
4
5
6
public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

如何使用Html.DropDownList扩展方法使用这些值创建下拉列表?

或者我的最佳选择是简单地创建一个for循环并手动创建HTML元素?


对于MVC v5.1,使用html.enumDropDownListfor

1
2
3
4
@Html.EnumDropDownListFor(
    x => x.YourEnumField,
   "Select My Type",
    new { @class ="form-control" })

对于MVC v5,使用EnumHelper

1
2
3
4
@Html.DropDownList("MyType",
   EnumHelper.GetSelectList(typeof(MyType)) ,
  "Select My Type",
   new { @class ="form-control" })

MVC 5及以下

我把Rune的答案卷进了一个扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
namespace MyApp.Common
{
    public static class MyExtensions{
        public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        {
            var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                select new { Id = e, Name = e.ToString() };
            return new SelectList(values,"Id","Name", enumObj);
        }
    }
}

这允许您写:

1
ViewData["taskStatus"] = task.Status.ToSelectList();

using MyApp.Common签署


我知道我迟到了,但我想你可能会发现这个变量很有用,因为这个变量还允许你在下拉列表中使用描述性字符串而不是枚举常量。为此,请用[System.ComponentModel.Description]属性修饰每个枚举项。

例如:

1
2
3
4
5
6
7
8
9
10
11
public enum TestEnum
{
  [Description("Full test")]
  FullTest,

  [Description("Incomplete or partial test")]
  PartialTest,

  [Description("No test performed")]
  None
}

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Reflection;
using System.ComponentModel;
using System.Linq.Expressions;

 ...

 private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
    {
        Type realModelType = modelMetadata.ModelType;

        Type underlyingType = Nullable.GetUnderlyingType(realModelType);
        if (underlyingType != null)
        {
            realModelType = underlyingType;
        }
        return realModelType;
    }

    private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text ="", Value ="" } };

    public static string GetEnumDescription<TEnum>(TEnum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if ((attributes != null) && (attributes.Length > 0))
            return attributes[0].Description;
        else
            return value.ToString();
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
    {
        return EnumDropDownListFor(htmlHelper, expression, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        Type enumType = GetNonNullableModelType(metadata);
        IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();

        IEnumerable<SelectListItem> items = from value in values
            select new SelectListItem
            {
                Text = GetEnumDescription(value),
                Value = value.ToString(),
                Selected = value.Equals(metadata.Model)
            };

        // If the enum is nullable, add an 'empty' item to the collection
        if (metadata.IsNullableValueType)
            items = SingleEmptyItem.Concat(items);

        return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
    }

然后可以在视图中执行此操作:

1
@Html.EnumDropDownListFor(model => model.MyEnumProperty)

希望这对你有帮助!

**编辑2014年1月23日:微软刚刚发布了MVC 5.1,它现在有一个EnumDropDownList功能。遗憾的是,它似乎不尊重[description]属性,因此上面的代码仍然存在。请参阅Microsoft MVC 5.1发行说明中的枚举部分。

更新:它确实支持显示属性[Display(Name ="Sample")],所以可以使用它。

[更新-刚刚注意到这一点,这里的代码看起来像是代码的扩展版本:https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/,并添加了一些内容。如果是这样,归属似乎是公平的;-)]


在ASP.NET MVC 5.1中,他们添加了EnumDropDownListFor()助手,因此不需要自定义扩展:

模型:

1
2
3
4
5
6
7
public enum MyEnum
{
    [Display(Name ="First Value - desc..")]
    FirstValue,
    [Display(Name ="Second Value - desc...")]
    SecondValue
}

观点:

1
@Html.EnumDropDownListFor(model => model.MyEnum)

使用标记助手(ASP.NET MVC 6):

1
<select asp-for="@Model.SelectedValue" asp-items="Html.GetEnumSelectList<MyEnum>()">


我碰到了同样的问题,发现了这个问题,并且认为ash提供的解决方案不是我想要的;与内置的Html.DropDownList()函数相比,必须自己创建HTML意味着更少的灵活性。

事实证明,C 3等使这相当容易。我有一个叫enumTaskStatus

1
2
3
var statuses = from TaskStatus s in Enum.GetValues(typeof(TaskStatus))
               select new { ID = s, Name = s.ToString() };
ViewData["taskStatus"] = new SelectList(statuses,"ID","Name", task.Status);

这就创建了一个很好的ol'SelectList,可以像在视图中那样使用:

1
<td>Status:</td><td><%=Html.DropDownList("taskStatus")%></td></tr>

匿名类型和LINQ使得这个更加优雅。无意冒犯,阿什。:)


下面是一个更好的封装解决方案:

https://www.spicelogic.com/blog/enum-dropdownlistfor-asp-net-mvc-5

假设这是你的模型:

enter image description here

样品使用情况:

enter image description here

生成的用户界面:enter image description here

和生成的HTML

enter image description here

帮助程序扩展源代码快照:

enter image description here

您可以从我提供的链接下载示例项目。

编辑:代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static class EnumEditorHtmlHelper
{
    /// <summary>
    /// Creates the DropDown List (HTML Select Element) from LINQ
    /// Expression where the expression returns an Enum type.
    /// </summary>
    /// <typeparam name="TModel">The type of the model.</typeparam>
    /// <typeparam name="TProperty">The type of the property.</typeparam>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <param name="expression">The expression.</param>
    /// <returns></returns>
    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression)
        where TModel : class
    {
        TProperty value = htmlHelper.ViewData.Model == null
            ? default(TProperty)
            : expression.Compile()(htmlHelper.ViewData.Model);
        string selected = value == null ? String.Empty : value.ToString();
        return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected));
    }

    /// <summary>
    /// Creates the select list.
    /// </summary>
    /// <param name="enumType">Type of the enum.</param>
    /// <param name="selectedItem">The selected item.</param>
    /// <returns></returns>
    private static IEnumerable<SelectListItem> createSelectList(Type enumType, string selectedItem)
    {
        return (from object item in Enum.GetValues(enumType)
                let fi = enumType.GetField(item.ToString())
                let attribute = fi.GetCustomAttributes(typeof (DescriptionAttribute), true).FirstOrDefault()
                let title = attribute == null ? item.ToString() : ((DescriptionAttribute) attribute).Description
                select new SelectListItem
                  {
                      Value = item.ToString(),
                      Text = title,
                      Selected = selectedItem == item.ToString()
                  }).ToList();
    }
}


html.dropdownlistfor只需要IEnumerable,因此普莱斯解决方案的替代方案如下。这将允许您简单地写:

1
@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())

[其中,selecteditemtype是类型为itemtype的模型上的字段,并且您的模型为非空]

此外,您不需要对扩展方法进行泛型化,因为您可以使用EnumValue.getType()而不是typeof(t)。

编辑:这里也集成了Simon的解决方案,包括描述扩展方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static class EnumExtensions
{
    public static IEnumerable<SelectListItem> ToSelectList(this Enum enumValue)
    {
        return from Enum e in Enum.GetValues(enumValue.GetType())
               select new SelectListItem
               {
                   Selected = e.Equals(enumValue),
                   Text = e.ToDescription(),
                   Value = e.ToString()
               };
    }

    public static string ToDescription(this Enum value)
    {
        var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
}


因此,如果您正在寻找简单和简单的扩展函数,那么就不需要扩展函数了。我就是这么做的

1
<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>

其中,xxxxx.sites.yyyy.models.state是枚举

可能更好地执行助手功能,但当时间较短时,这将完成任务。


展开prise和rune的答案,如果希望将所选列表项的value属性映射到枚举类型的整数值,而不是字符串值,请使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static SelectList ToSelectList<T, TU>(T enumObj)
    where T : struct
    where TU : struct
{
    if(!typeof(T).IsEnum) throw new ArgumentException("Enum is required.","enumObj");

    var values = from T e in Enum.GetValues(typeof(T))
                 select new {
                    Value = (TU)Convert.ChangeType(e, typeof(TU)),
                    Text = e.ToString()
                 };

    return new SelectList(values,"Value","Text", enumObj);
}

我们可以将每个枚举值视为一个tenum对象,而不是将其视为一个对象,然后将其转换为整数以获取未绑定的值。

注:我还添加了一个泛型类型约束来限制只能对结构(枚举的基类型)使用此扩展的类型,并添加了一个运行时类型验证来确保传入的结构确实是一个枚举。

2012年10月23日更新:为基础类型添加了泛型类型参数,并修复了影响.NET 4+的非编译问题。


解决了用普莱斯扩展方法获取数字而不是文本的问题。

1
2
3
4
5
6
7
8
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
  var values = from TEnum e in Enum.GetValues(typeof(TEnum))
               select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
                         , Name = e.ToString() };

  return new SelectList(values,"Id","Name", enumObj);
}


我找到的最好的解决办法是把这个博客和西蒙·戈德斯通的答案结合起来。

这允许在模型中使用枚举。其基本思想是使用整数属性和枚举,并模拟整数属性。

然后使用[System.ComponentModel.Description]属性用显示文本注释模型,并在视图中使用"EnumDropDownList"扩展名。

这使得视图和模型都非常可读和可维护。

模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public enum YesPartialNoEnum
{
    [Description("Yes")]
    Yes,
    [Description("Still undecided")]
    Partial,
    [Description("No")]
    No
}

//........

[Display(Name ="The label for my dropdown list")]
public virtual Nullable<YesPartialNoEnum> CuriousQuestion{ get; set; }
public virtual Nullable<int> CuriousQuestionId
{
    get { return (Nullable<int>)CuriousQuestion; }
    set { CuriousQuestion = (Nullable<YesPartialNoEnum>)value; }
}

观点:

1
2
3
4
5
6
@using MyProject.Extensions
{
//...
    @Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}

扩展名(直接来自Simon Goldstone的回答,完整性请参见此处):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;

namespace MyProject.Extensions
{
    //Extension methods must be defined in a static class
    public static class MvcExtensions
    {
        private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
        {
            Type realModelType = modelMetadata.ModelType;

            Type underlyingType = Nullable.GetUnderlyingType(realModelType);
            if (underlyingType != null)
            {
                realModelType = underlyingType;
            }
            return realModelType;
        }

        private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text ="", Value ="" } };

        public static string GetEnumDescription<TEnum>(TEnum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());

            DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if ((attributes != null) && (attributes.Length > 0))
                return attributes[0].Description;
            else
                return value.ToString();
        }

        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
        {
            return EnumDropDownListFor(htmlHelper, expression, null);
        }

        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            Type enumType = GetNonNullableModelType(metadata);
            IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();

            IEnumerable<SelectListItem> items = from value in values
                                                select new SelectListItem
                                                {
                                                    Text = GetEnumDescription(value),
                                                    Value = value.ToString(),
                                                    Selected = value.Equals(metadata.Model)
                                                };

            // If the enum is nullable, add an 'empty' item to the collection
            if (metadata.IsNullableValueType)
                items = SingleEmptyItem.Concat(items);

            return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
        }
    }
}


一个非常简单的方法来完成这项工作-没有所有的扩展的东西,似乎是过度杀戮是:

你的枚举:

1
2
3
4
5
6
7
    public enum SelectedLevel
    {
       Level1,
       Level2,
       Level3,
       Level4
    }

在控制器内部,将枚举绑定到列表:

1
    List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();

然后把它扔到一个视窗袋里:

1
    ViewBag.RequiredLevel = new SelectList(myLevels);

最后简单地将其绑定到视图:

1
    @Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class ="form-control" })

这是迄今为止我发现的最简单的方法,不需要任何扩展或任何疯狂的东西。

更新:见下面的安德鲁斯评论。


你想看看使用类似于Enum.GetValues的东西


1
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))


这是修改后的rune&price答案,以使用枚举int值作为ID。

样本枚举:

1
2
3
4
5
6
public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

扩展方法:

1
2
3
4
5
6
7
    public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
    {
        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                     select new { Id = (int)Enum.Parse(typeof(TEnum), e.ToString()), Name = e.ToString() };

        return new SelectList(values,"Id","Name", (int)Enum.Parse(typeof(TEnum), enumObj.ToString()));
    }

使用示例:

1
 <%=  Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>

请记住导入包含扩展方法的命名空间

1
<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>

生成的HTML示例:

1
2
3
4
5
<select id="MyEnumList" name="MyEnumList">
    <option value="1">Movie</option>
    <option selected="selected" value="2">Game</option>
    <option value="3">Book </option>
</select>

请注意,用于调用ToSelectList的项是选中的项。


这是剃须刀的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
@{
    var itemTypesList = new List<SelectListItem>();
    itemTypesList.AddRange(Enum.GetValues(typeof(ItemTypes)).Cast<ItemTypes>().Select(
                (item, index) => new SelectListItem
                {
                    Text = item.ToString(),
                    Value = (index).ToString(),
                    Selected = Model.ItemTypeId == index
                }).ToList());
 }


@Html.DropDownList("ItemTypeId", itemTypesList)


现在,在MVC 5.1到@Html.EnumDropDownListFor()中,该功能是开箱即用的。

检查以下链接:

https://docs.microsoft.com/en-us/aspnet/mvc/overview/releases/mvc51发行说明枚举

很遗憾,微软花了5年的时间才实现了这类功能,根据上面的投票结果,这类功能非常受欢迎!


好吧,我参加聚会真的很晚了,但就其价值而言,我已经在博客上讨论了这个主题,我创建了一个EnumHelper类,可以很容易地进行转换。

http://jnye.co/posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23

在控制器中:

1
2
3
4
5
//If you don't have an enum value use the type
ViewBag.DropDownList = EnumHelper.SelectListFor<MyEnum>();

//If you do have an enum value use the value (the value will be marked as selected)    
ViewBag.DropDownList = EnumHelper.SelectListFor(MyEnum.MyEnumValue);

在你看来:

1
2
3
@Html.DropDownList("DropDownList")
@* OR *@
@Html.DropDownListFor(m => m.Property, ViewBag.DropDownList as SelectList, null)

帮助程序类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public static class EnumHelper
{
    // Get the value of the description attribute if the  
    // enum has one, otherwise use the value.  
    public static string GetDescription<TEnum>(this TEnum value)
    {
        var fi = value.GetType().GetField(value.ToString());

        if (fi != null)
        {
            var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes.Length > 0)
            {
                return attributes[0].Description;
            }
        }

        return value.ToString();
    }

    /// <summary>
    /// Build a select list for an enum
    /// </summary>
    public static SelectList SelectListFor<T>() where T : struct
    {
        Type t = typeof(T);
        return !t.IsEnum ? null
                         : new SelectList(BuildSelectListItems(t),"Value","Text");
    }

    /// <summary>
    /// Build a select list for an enum with a particular value selected
    /// </summary>
    public static SelectList SelectListFor<T>(T selected) where T : struct
    {
        Type t = typeof(T);
        return !t.IsEnum ? null
                         : new SelectList(BuildSelectListItems(t),"Text","Value", selected.ToString());
    }

    private static IEnumerable<SelectListItem> BuildSelectListItems(Type t)
    {
        return Enum.GetValues(t)
                   .Cast<Enum>()
                   .Select(e => new SelectListItem { Value = e.ToString(), Text = e.GetDescription() });
    }
}

基于Simon的答案,类似的方法是从资源文件中获取枚举值,而不是在枚举本身的描述属性中显示。如果您的站点需要用多种语言呈现,并且如果您要有一个特定的枚举资源文件,您可以更进一步,在您的枚举中只包含枚举值,并通过一个惯例(如[EnumName]u[EnumValue]——最终减少键入)从扩展中引用这些值,这是很有帮助的!

然后扩展如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static IHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{            
    var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);

    var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;

    var enumValues = Enum.GetValues(enumType).Cast<object>();

    var items = from enumValue in enumValues                        
                select new SelectListItem
                {
                    Text = GetResourceValueForEnumValue(enumValue),
                    Value = ((int)enumValue).ToString(),
                    Selected = enumValue.Equals(metadata.Model)
                };


    return html.DropDownListFor(expression, items, string.Empty, null);
}

private static string GetResourceValueForEnumValue<TEnum>(TEnum enumValue)
{
    var key = string.Format("{0}_{1}", enumValue.GetType().Name, enumValue);

    return Enums.ResourceManager.GetString(key) ?? enumValue.ToString();
}

Enums.resx文件中的资源看起来像项目类型电影:电影

我喜欢做的另一件事是,我不想直接调用扩展方法,而是用@html.editorfor(x=>x.myproperty)调用它,或者理想情况下只使用一个整洁的@html.editorformodel()中的整个表单。为此,我将字符串模板更改为如下所示

1
2
3
4
5
6
7
@using MVCProject.Extensions

@{
    var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;

    @(typeof (Enum).IsAssignableFrom(type) ? Html.EnumDropDownListFor(x => x) : Html.TextBoxFor(x => x))
}

如果你对此感兴趣,我会在我的博客上给出更详细的答案:

Create a dropdown list from an Enum in Asp.Net MVC


在.NET核心中,您只需使用:

1
@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList<MyEnum>())


我已经很晚了,但我只是找到了一个非常酷的方法来完成这一行代码,如果你愿意添加无约束的旋律nuget包(一个很好的,来自jon skeet的小库)。

此解决方案更好,因为:

  • 它确保(使用泛型类型约束)该值实际上是枚举值(由于旋律不受约束)
  • 避免不必要的拳击(由于旋律不受约束)
  • 它缓存所有描述,以避免在每次调用时使用反射(由于旋律不受约束)
  • 它的代码比其他解决方案少!
  • 因此,以下是实现这一目标的步骤:

  • 在包管理器控制台中,"安装包未经培训的日志"
  • 在模型上添加属性,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    //Replace"YourEnum" with the type of your enum
    public IEnumerable<SelectListItem> AllItems
    {
        get
        {
            return Enums.GetValues<YourEnum>().Select(enumValue => new SelectListItem { Value = enumValue.ToString(), Text = enumValue.GetDescription() });
        }
    }
  • 既然模型中已经公开了selectListItem的列表,那么可以使用@html.dropdownlist或@html.dropdownlist将此属性用作源。


    如果要添加本地化支持,只需将s.ToString()方法更改为如下所示:

    1
    2
    3
    ResourceManager rManager = new ResourceManager(typeof(Resources));
    var dayTypes = from OperatorCalendarDay.OperatorDayType s in Enum.GetValues(typeof(OperatorCalendarDay.OperatorDayType))
                   select new { ID = s, Name = rManager.GetString(s.ToString()) };

    在这里,typeof(resources)是要加载的资源,然后得到本地化字符串,如果枚举器具有多个单词的值,那么也很有用。


    此扩展方法的另一个修复方法-当前版本没有选择枚举的当前值。我修改了最后一行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static SelectList ToSelectList<TEnum>(this TEnum enumObj) where TEnum : struct
        {
            if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.","enumObj");

            var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                           select new
                           {
                               ID = (int)Enum.Parse(typeof(TEnum), e.ToString()),
                               Name = e.ToString()
                           };


            return new SelectList(values,"ID","Name", ((int)Enum.Parse(typeof(TEnum), enumObj.ToString())).ToString());
        }

    我在这里找到了答案。但是,我的一些枚举具有[Description(...)]属性,因此我修改了代码以提供支持:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
        enum Abc
        {
            [Description("Cba")]
            Abc,

            Def
        }


        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, TEnum selectedValue)
        {
            IEnumerable<TEnum> values = Enum.GetValues(typeof(TEnum))
                .Cast<TEnum>();

            List<SelectListItem> items = new List<SelectListItem>();
            foreach (var value in values)
            {
                string text = value.ToString();

                var member = typeof(TEnum).GetMember(value.ToString());
                if (member.Count() > 0)
                {
                    var customAttributes = member[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (customAttributes.Count() > 0)
                    {
                        text = ((DescriptionAttribute)customAttributes[0]).Description;
                    }
                }

                items.Add(new SelectListItem
                {
                    Text = text,
                    Value = value.ToString(),
                    Selected = (value.Equals(selectedValue))
                });
            }

            return htmlHelper.DropDownList(
                name,
                items
                );
        }

    希望有帮助。


    这是我的helper方法版本。我用这个:

    1
    2
    var values = from int e in Enum.GetValues(typeof(TEnum))
                 select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };

    而不是:

    1
    2
    3
    var values = from TEnum e in Enum.GetValues(typeof(TEnum))
               select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
                         , Name = e.ToString() };

    这里是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static SelectList ToSelectList<TEnum>(this TEnum self) where TEnum : struct
        {
            if (!typeof(TEnum).IsEnum)
            {
                throw new ArgumentException("self must be enum","self");
            }

            Type t = typeof(TEnum);

            var values = from int e in Enum.GetValues(typeof(TEnum))
                         select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };

            return new SelectList(values,"ID","Name", self);
        }


    您也可以在griffin.mvcontrib中使用我的自定义htmlhelpers。以下代码:

    1
    2
    3
    @Html2.CheckBoxesFor(model => model.InputType) <br />
    @Html2.RadioButtonsFor(model => model.InputType) <br />
    @Html2.DropdownFor(model => model.InputType) <br />

    生成:

    enter image description here

    https://github.com/jgauffin/griffin.mvcontrib网站


    @西蒙戈德斯通:谢谢你的解决方案,它可以完美地应用于我的案件。唯一的问题是我必须把它翻译成vb。但是现在已经完成了,为了节省别人的时间(如果他们需要的话),我把它放在这里:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    Imports System.Runtime.CompilerServices
    Imports System.ComponentModel
    Imports System.Linq.Expressions

    Public Module HtmlHelpers
        Private Function GetNonNullableModelType(modelMetadata As ModelMetadata) As Type
            Dim realModelType = modelMetadata.ModelType

            Dim underlyingType = Nullable.GetUnderlyingType(realModelType)

            If Not underlyingType Is Nothing Then
                realModelType = underlyingType
            End If

            Return realModelType
        End Function

        Private ReadOnly SingleEmptyItem() As SelectListItem = {New SelectListItem() With {.Text ="", .Value =""}}

        Private Function GetEnumDescription(Of TEnum)(value As TEnum) As String
            Dim fi = value.GetType().GetField(value.ToString())

            Dim attributes = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())

            If Not attributes Is Nothing AndAlso attributes.Length > 0 Then
                Return attributes(0).Description
            Else
                Return value.ToString()
            End If
        End Function

        <Extension()>
        Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum))) As MvcHtmlString
            Return EnumDropDownListFor(htmlHelper, expression, Nothing)
        End Function

        <Extension()>
        Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum)), htmlAttributes As Object) As MvcHtmlString
            Dim metaData As ModelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
            Dim enumType As Type = GetNonNullableModelType(metaData)
            Dim values As IEnumerable(Of TEnum) = [Enum].GetValues(enumType).Cast(Of TEnum)()

            Dim items As IEnumerable(Of SelectListItem) = From value In values
                Select New SelectListItem With
                {
                    .Text = GetEnumDescription(value),
                    .Value = value.ToString(),
                    .Selected = value.Equals(metaData.Model)
                }

            ' If the enum is nullable, add an 'empty' item to the collection
            If metaData.IsNullableValueType Then
                items = SingleEmptyItem.Concat(items)
            End If

            Return htmlHelper.DropDownListFor(expression, items, htmlAttributes)
        End Function
    End Module

    结束你这样使用它:

    1
    @Html.EnumDropDownListFor(Function(model) (model.EnumField))

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Html.DropDownListFor(model => model.MaritalStatus, new List<SelectListItem>
    {  

    new SelectListItem { Text ="----Select----", Value ="-1" },


    new SelectListItem { Text ="Marrid", Value ="M" },


     new SelectListItem { Text ="Single", Value ="S" }

    })


    我最终创建了扩展方法来做本质上是接受答案的事情。gist的后半部分专门处理枚举。

    网址:https://gist.github.com/3813767


    1
    2
    3
    4
    @Html.DropdownListFor(model=model->Gender,new List<SelectListItem>
    {
     new ListItem{Text="Male",Value="Male
    <hr><P>我已经完成了以下工作并成功地工作:</P><ul><li>在view.cshtml中:</li></ul><P>@型号mymodel.cs</P>[cc lang="
    csharp"]@Html.EnumDropDownListFor(m=>m.MyItemType )
    • 在模型中:MyMeal.CS

    public ItemTypes MyItemType { get; set; }


    在MVC4中,我想要这个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Html.DropDownList("RefType", new SelectList(Enum.GetValues(typeof(WebAPIApp.Models.RefType)))," Select", new { @class ="form-control" })

    public enum RefType
        {
            Web = 3,
            API = 4,
            Security = 5,
            FE = 6
        }

        public class Reference
        {
            public int Id { get; set; }
            public RefType RefType { get; set; }
        }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
            ////  ViewModel

            public class RegisterViewModel
              {

            public RegisterViewModel()
              {
                  ActionsList = new List<SelectListItem>();
              }

            public IEnumerable<SelectListItem> ActionsList { get; set; }

            public string StudentGrade { get; set; }

               }

           //// Enum Class

            public enum GradeTypes
                 {
                   A,
                   B,
                   C,
                   D,
                   E,
                   F,
                   G,
                   H
                }

             ////Controller action

               public ActionResult Student()
                   {
        RegisterViewModel vm = new RegisterViewModel();
        IEnumerable<GradeTypes> actionTypes = Enum.GetValues(typeof(GradeTypes))
                                             .Cast<GradeTypes>();                  
        vm.ActionsList = from action in actionTypes
                         select new SelectListItem
                         {
                             Text = action.ToString(),
                             Value = action.ToString()
                         };
                  return View(vm);
                   }

             ////// View Action

       
                                <label class="col-lg-2 control-label" for="hobies">Student Grade:</label>
                               
                                   @Html.DropDownListFor(model => model.StudentGrade, Model.ActionsList, new { @class ="form-control" })

    我想用另一种方式回答这个问题,用户不需要在controllerLinq表达式中做任何事情。这种方式。。。

    我有一台ENUM

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public enum AccessLevelEnum
        {
            /// <summary>
            /// The user cannot access
            /// </summary>
            [EnumMember, Description("No Access")]
            NoAccess = 0x0,

            /// <summary>
            /// The user can read the entire record in question
            /// </summary>
            [EnumMember, Description("Read Only")]
            ReadOnly = 0x01,

            /// <summary>
            /// The user can read or write
            /// </summary>
            [EnumMember, Description("Read / Modify")]
            ReadModify = 0x02,

            /// <summary>
            /// User can create new records, modify and read existing ones
            /// </summary>
            [EnumMember, Description("Create / Read / Modify")]
            CreateReadModify = 0x04,

            /// <summary>
            /// User can read, write, or delete
            /// </summary>
            [EnumMember, Description("Create / Read / Modify / Delete")]
            CreateReadModifyDelete = 0x08,

            /*/// <summary>
            /// User can read, write, or delete
            /// </summary>
            [EnumMember, Description("Create / Read / Modify / Delete / Verify / Edit Capture Value")]
            CreateReadModifyDeleteVerify = 0x16*/

        }

    现在我可以简单地用这个ENUM创建一个dropdown

    1
    @Html.DropDownList("accessLevel",new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class ="form-control" })

    1
    @Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class ="form-control" })

    如果要选择索引,请尝试此操作

    1
    @Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum)) , AccessLevelEnum.NoAccess ),new { @class ="form-control" })

    这里我使用AccessLevelEnum.NoAccess作为默认选择下拉列表的额外参数。


    这里是MartinFaartoft的变体,您可以在其中放置自定义标签,这对于本地化很好。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static class EnumHtmlHelper
    {
        public static SelectList ToSelectList<TEnum>(this TEnum enumObj, Dictionary<int, string> customLabels)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        {
            var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                         select new { Id = e, Name = customLabels.First(x => x.Key == Convert.ToInt32(e)).Value.ToString() };

            return new SelectList(values,"Id","Name", enumObj);
        }
    }

    使用视图:

    1
    2
    3
    4
    5
    6
    7
    @Html.DropDownListFor(m => m.Category, Model.Category.ToSelectList(new Dictionary<int, string>() {
              { 1, ContactResStrings.FeedbackCategory },
              { 2, ContactResStrings.ComplainCategory },
              { 3, ContactResStrings.CommentCategory },
              { 4, ContactResStrings.OtherCategory }
          }), new { @class ="form-control" })
    @Html.ValidationMessageFor(m => m.Category)


    1-创建枚举

    1
    2
    3
    4
    5
    public enum LicenseType
    {
        xxx = 1,
        yyy = 2
    }

    2-创建服务类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class LicenseTypeEnumService
        {

            public static Dictionary<int, string> GetAll()
            {

                var licenseTypes = new Dictionary<int, string>();

                licenseTypes.Add((int)LicenseType.xxx,"xxx");
                licenseTypes.Add((int)LicenseType.yyy,"yyy");

                return licenseTypes;

            }

            public static string GetById(int id)
            {

                var q = (from p in this.GetAll() where p.Key == id select p).Single();
                return q.Value;

            }

        }

    3-在控制器中设置可视包

    1
    2
    var licenseTypes = LicenseTypeEnumService.GetAll();
    ViewBag.LicenseTypes = new SelectList(licenseTypes,"Key","Value");

    4-绑定下拉列表

    1
    @Html.DropDownList("LicenseType", (SelectList)ViewBag.LicenseTypes)


    更新-我建议使用下面的rune建议,而不是这个选项!

    我假设你想要如下的东西:

    1
    2
    3
    4
    5
    <select name="blah">
        <option value="1">Movie</option>
        <option value="2">Game</option>
        <option value="3">Book</option>
    </select>

    您可以使用如下扩展方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public static string DropdownEnum(this System.Web.Mvc.HtmlHelper helper,
                                      Enum values)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        sb.Append("<select name="blah">");
        string[] names = Enum.GetNames(values.GetType());
        foreach(string name in names)
        {
            sb.Append("<option value="");
            sb.Append(((int)Enum.Parse(values.GetType(), name)).ToString());
            sb.Append("
    ">");
            sb.Append(name);
            sb.Append("</option>");
        }
        sb.Append("</select>");
        return sb.ToString();
    }

    但像这样的东西是不可本地化的(即很难翻译成另一种语言)。

    注意:需要使用枚举实例调用静态方法,即Html.DropdownEnum(ItemTypes.Movie);

    也许有一种更优雅的方法可以做到这一点,但上述方法确实有效。