如何从ASP.NET MVC中的枚举创建下拉列表?

Kev*_*ang 653 c# asp.net asp.net-mvc

我正在尝试使用Html.DropDownList扩展方法,但无法弄清楚如何将它与枚举一起使用.

假设我有一个这样的枚举:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}
Run Code Online (Sandbox Code Playgroud)

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

或者我最好的办法是简单地创建一个for循环并手动创建Html元素?

Mar*_*oft 819

对于MVC v5.1,使用Html.EnumDropDownListFor

@Html.EnumDropDownListFor(
    x => x.YourEnumField,
    "Select My Type", 
    new { @class = "form-control" })
Run Code Online (Sandbox Code Playgroud)

对于MVC v5,请使用EnumHelper

@Html.DropDownList("MyType", 
   EnumHelper.GetSelectList(typeof(MyType)) , 
   "Select My Type", 
   new { @class = "form-control" })
Run Code Online (Sandbox Code Playgroud)

对于MVC 5及更低版本

我将Rune的答案转换为扩展方法:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许你写:

ViewData["taskStatus"] = task.Status.ToSelectList();
Run Code Online (Sandbox Code Playgroud)

通过 using MyApp.Common

  • 我不能让它工作,你能帮忙吗?当我做Post.PostType.ToSelectList(); 它不承认扩展? (13认同)
  • 您可以使用以下内容对其进行一些限制:其中T:struct,IConvertible请参阅:http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum (8认同)
  • 这很酷.如果有人正在努力实施这里我是如何做到的.在HtmlHelpers文件夹中添加了一个EnumHelpers类.使用上面的代码.根据@TodK建议添加命名空间:<add namespace ="xxx.HtmlHelpers"/>.然后我在剃刀页面中使用它:@ Html.DropDownListFor(model => model.Status,@ Model.Status.ToSelectList())HTH (8认同)
  • 请注意,在较新的`ASP.NET MVC`中有一种本地方式:http://stackoverflow.com/a/22295360/1361084 (6认同)
  • 我也无法让这个工作.状态是您的Enum属性在任务类上?这不是枚举值之一吗? (3认同)

Sim*_*one 351

我知道我在这方面迟到了,但是你认为这个变种很有用,因为这个变体也允许你在下拉列表中使用描述性字符串而不是枚举常量.为此,请使用[System.ComponentModel.Description]属性装饰每个枚举条目.

例如:

public enum TestEnum
{
  [Description("Full test")]
  FullTest,

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

  [Description("No test performed")]
  None
}
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

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);
    }
Run Code Online (Sandbox Code Playgroud)

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

@Html.EnumDropDownListFor(model => model.MyEnumProperty)
Run Code Online (Sandbox Code Playgroud)

希望这对你有所帮助!

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

更新:它确实支持Display属性[Display(Name = "Sample")],因此可以使用它.

[更新 - 只是注意到这一点,代码看起来像这里的代码的扩展版本:https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- dropdownlist-helper-for-enums /,有几个附加功能.如果是这样,归属似乎是公平的;-)]

  • Visual Studio有一个奇怪的错误,如果你不引用`System.Web.Mvc.Html`,那么就说找不到'DropDownListFor`,但它也无法解决它.你必须手动执行`using System.Web.Mvc.Html;`.你好吗? (42认同)
  • +1我在这里找到了最有用的所有答案.我能够将其转换为高度可重用的代码片段.谢谢! (27认同)
  • 新的MVC 5.1 EnumDropDownListFor不使用[Description("")]但它确实使用[Display(Name ="")]!请享用 :) (17认同)

Ofi*_*ris 188

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

型号:

public enum MyEnum
{
    [Display(Name = "First Value - desc..")]
    FirstValue,
    [Display(Name = "Second Value - desc...")]
    SecondValue
}
Run Code Online (Sandbox Code Playgroud)

查看:

@Html.EnumDropDownListFor(model => model.MyEnum)
Run Code Online (Sandbox Code Playgroud)

使用Tag Helper(ASP.NET MVC 6):

<select asp-for="@Model.SelectedValue" asp-items="Html.GetEnumSelectList<MyEnum>()">
Run Code Online (Sandbox Code Playgroud)

  • 这需要以某种方式提升到第一位 (19认同)
  • 您应该创建一个特定于MVC 5.1的新问题并将其作为答案,然后向我发送一个指向该帖子的链接,以便我可以赞成收藏. (3认同)
  • 我不喜欢EnumDropDownListFor()的是它将枚举的int值保存到DB中,而不是文本,所以如果你选择添加一个新的枚举项,它必须放在列表的末尾,以免松散保存的数据库int值与枚举项的原始位置的关系.如果保存文本,则这是不必要的限制.另外,我宁愿能够查看数据库并查看文本,而不是在那里我必须在其他地方查找文本值.否则这个html助手使用起来非常方便. (2认同)
  • @Giovanni - 您可以指定自己的数值. (2认同)
  • @Giovanni严格的设计应该为每个枚举条目分配值(如果它很重要),否则该值应该不重要(因此将新的值放在最后应该不是问题)。在节省存储空间和提高性能(执行某些搜索时)方面,保存 int 值会更好。 (2认同)

Run*_*sen 127

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

原来C#3等让这很容易.我有一个enumTaskStatus:

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);
Run Code Online (Sandbox Code Playgroud)

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

<td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr>
Run Code Online (Sandbox Code Playgroud)

匿名类型和LINQ使这个更优雅恕我直言.Ash,没有违法行为.:)

  • @BarbarosAlp要将ID作为一个数字,您需要将枚举转换为int:`select new {ID =(int)s,Name = s.ToString()};` (5认同)

Emr*_*ain 61

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

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

这里说的是你的型号:

在此输入图像描述

样品用法:

在此输入图像描述

生成的UI: 在此输入图像描述

并生成HTML

在此输入图像描述

Helper扩展源代码快照:

在此输入图像描述

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

编辑:这是代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 只是我的意见,但我认为这个答案比接受的答案要清晰得多.我特别喜欢使用Description属性的选项.我添加了代码,以便人们可以复制/粘贴它而无需下载. (2认同)

Zai*_*sud 47

Html.DropDownListFor只需要一个IEnumerable,因此Prize解决方案的替代方案如下.这将允许您简单地写:

@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())
Run Code Online (Sandbox Code Playgroud)

[其中SelectedItemType是类型为ItemTypes的模型上的字段,并且您的模型为非null]

此外,您实际上不需要对扩展方法进行泛化,因为您可以使用enumValue.GetType()而不是typeof(T).

编辑:此处集成了Simon的解决方案,并包含ToDescription扩展方法.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*uth 32

所以没有扩展功能,如果你正在寻找简单和容易..这就是我做的

<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>
Run Code Online (Sandbox Code Playgroud)

其中XXXXX.Sites.YYYY.Models.State是一个枚举

可能更好地做辅助功能,但是当时间很短时,这将完成工作.

  • 应该能够将具有所选值的第二个参数传递给新的SelectList(IEnumerable,object)函数.MSDN Dococumentation:http://msdn.microsoft.com/en-us/library/dd460123.aspx (2认同)

Nat*_*lor 22

扩展Prize和Rune的答案,如果您希望将选择列表项的value属性映射到Enumeration类型的整数值,而不是字符串值,请使用以下代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

我们可以将其视为一个对象,然后将其转换为整数以获取未装箱的值,而不是将每个Enumeration值视为TEnum对象.

注意: 我还添加了一个泛型类型约束来限制此扩展可用的类型仅限于结构(Enum的基本类型),以及运行时类型验证,以确保传入的结构确实是一个枚举.

更新10/23/12: 为影响.NET 4+的基础类型和修复的非编译问题添加了泛型类型参数.

  • 获取错误"无法将类型'TEnum'转换为'int'". (3认同)

小智 10

使用Prize的扩展方法解决获取数字而不是文本的问题.

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);
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*ans 10

我找到的最佳解决方案是将此博客Simon Goldstone的答案相结合.

这允许在模型中使用枚举.本质上,我们的想法是使用整数属性以及枚举,并模拟整数属性.

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

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

模型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

视图:

@using MyProject.Extensions
{
//...
    @Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}
Run Code Online (Sandbox Code Playgroud)

扩展(直接来自Simon Goldstone的答案,包含在这里是为了完整性):

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Lou*_*caj 10

完成这项工作的一种非常简单的方法 - 没有看起来有点过分的所有扩展内容是这样的:

你的枚举:

    public enum SelectedLevel
    {
       Level1,
       Level2,
       Level3,
       Level4
    }
Run Code Online (Sandbox Code Playgroud)

在控制器内部将Enum绑定到List:

    List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();
Run Code Online (Sandbox Code Playgroud)

之后将其抛入ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);
Run Code Online (Sandbox Code Playgroud)

最后只需将其绑定到View:

    @Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class = "form-control" })
Run Code Online (Sandbox Code Playgroud)

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

更新:请参阅下面的安德鲁斯评论.

  • 这仅在您没有为枚举分配任何值时才有效.如果你有"Level1 = 1",那么下拉列表的值将是"Level1"而不是"1". (3认同)

Gar*_*ler 8

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


Gol*_*Age 8

在 .NET Core 中,你可以使用这个:

@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList<MyEnum>())
Run Code Online (Sandbox Code Playgroud)

  • 或者使用标签助手`&lt;select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList&lt;MyEnum&gt;()"&gt;&lt;/select&gt;`。 (2认同)

Mr.*_*kin 7

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


Mr.*_*ble 6

这是Rune&Prize答案被更改为使用Enum int值作为ID.

样本枚举:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}
Run Code Online (Sandbox Code Playgroud)

扩展方法:

    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()));
    }
Run Code Online (Sandbox Code Playgroud)

使用样本:

 <%=  Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>
Run Code Online (Sandbox Code Playgroud)

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

<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>
Run Code Online (Sandbox Code Playgroud)

生成的HTML示例:

<select id="MyEnumList" name="MyEnumList">
    <option value="1">Movie</option>
    <option selected="selected" value="2">Game</option>
    <option value="3">Book </option>
</select>
Run Code Online (Sandbox Code Playgroud)

请注意,用于调用ToSelectListon的项目是所选项目.


noo*_*otn 6

我在这方面已经很晚了,但我刚刚找到了一种非常酷的方法,可以用一行代码来完成此操作,如果您愿意添加Unconstrained Melody NuGet 包(来自 Jon Skeet 的一个不错的小型库)。

该解决方案更好,因为:

  1. 它确保(具有通用类型约束)该值确实是一个枚举值(由于不受约束的旋律)
  2. 它避免了不必要的拳击(由于不受约束的旋律)
  3. 它缓存所有描述以避免在每次调用时使用反射(由于不受约束的旋律)
  4. 它比其他解决方案的代码更少!

因此,以下是使其正常工作的步骤:

  1. 在包管理器控制台中,“Install-Package UnconstrainedMelody”
  2. 在您的模型上添加属性,如下所示:

    //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() });
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在您已经在模型上公开了 SelectListItem 的列表,您可以使用 @Html.DropDownList 或 @Html.DropDownListFor 将此属性用作源。


小智 5

这是Razor的版本:

@{
    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)
Run Code Online (Sandbox Code Playgroud)


Pau*_*ist 5

基于 Simon 的回答,类似的方法是从 Resource 文件中获取要显示的 Enum 值,而不是在 Enum 本身的描述属性中显示。如果您的网站需要以一种以上的语言呈现,并且如果您要为 Enum 提供特定的资源文件,则这很有用诸如 [EnumName]_[EnumValue] 之类的约定 - 最终减少输入!

扩展看起来像:

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();
}
Run Code Online (Sandbox Code Playgroud)

Enums.Resx 文件中的资源类似于 ItemTypes_Movie : Film

我喜欢做的另一件事是,我宁愿用@Html.EditorFor(x => x.MyProperty) 来调用它,而不是直接调用扩展方法,或者理想情况下只是拥有整个表单,以一个整洁的@ Html.EditorForModel()。为此,我将字符串模板更改为如下所示

@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))
}
Run Code Online (Sandbox Code Playgroud)

如果您对此感兴趣,我在我的博客上提供了更详细的答案:

http://paulthecyclist.com/2013/05/24/enum-dropdown/


Nin*_*Nye 5

好吧,我参加聚会真的很晚,但就其价值而言,我已经写了关于这个主题的博客,借此我创建了一个EnumHelper可以非常轻松地转换的类。

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

在您的控制器中:

//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);
Run Code Online (Sandbox Code Playgroud)

在您的视图中:

@Html.DropDownList("DropDownList")
@* OR *@
@Html.DropDownListFor(m => m.Property, ViewBag.DropDownList as SelectList, null)
Run Code Online (Sandbox Code Playgroud)

辅助类:

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() });
    }
}
Run Code Online (Sandbox Code Playgroud)


Laf*_*afi 5

现在,通过以下方式在MVC 5.1中可以立即使用此功能: @Html.EnumDropDownListFor()

检查以下链接:

https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/releases/mvc51-release-notes#Enum

根据上面的投票,微软花了5年的时间来实现如此受欢迎的功能,真是太可惜了!


Alk*_*sai 5

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

    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
            );
    }
Run Code Online (Sandbox Code Playgroud)

希望有帮助。