【问题标题】:How do you create a dropdownlist from an enum in ASP.NET MVC?如何从 ASP.NET MVC 中的枚举创建下拉列表?
【发布时间】:2010-09-28 03:47:51
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: c# asp.net asp.net-mvc


    【解决方案1】:

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

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

    对于 MVC v5 使用 EnumHelper

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

    适用于 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);
            }
        }
    }
    

    这允许你写:

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

    using MyApp.Common

    【讨论】:

    • 我无法让它工作,请你帮忙。当我做 Post.PostType.ToSelectList();它不识别扩展名?
    • 我也无法让它工作。 Status 是任务类上的 Enum 属性吗?这不是枚举值之一吗?
    • 您可以通过以下方式对其进行一些限制: where T : struct, IConvertible 请参阅:stackoverflow.com/questions/79126/…
    • 这很酷。如果有人在实施方面苦苦挣扎,这就是我的做法。向 HtmlHelpers 文件夹添加了 EnumHelpers 类。使用了上面的代码。根据@TodK 建议添加了命名空间:。然后我在像这样的剃须刀页面中使用它:@Html.DropDownListFor(model => model.Status, @Model.Status.ToSelectList()) HTH
    • 请注意,在较新的ASP.NET MVC 中有一种本地方式:stackoverflow.com/a/22295360/1361084
    【解决方案2】:

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

    例如:

    public enum TestEnum
    {
      [Description("Full test")]
      FullTest,
    
      [Description("Incomplete or partial test")]
      PartialTest,
    
      [Description("No test performed")]
      None
    }
    

    这是我的代码:

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

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

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

    希望对您有所帮助!

    **EDIT 2014-JAN-23:Microsoft 刚刚发布了 MVC 5.1,它现在具有 EnumDropDownListFor 功能。遗憾的是,它似乎不尊重 [Description] 属性,因此上面的代码仍然有效。请参阅 Enum section in Microsoft 的 MVC 5.1 发行说明。

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

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

    【讨论】:

    • +1 我发现这是这里所有答案中最有用的。我能够把它变成一段高度可重用的代码。谢谢!
    • Visual Studio 有一个奇怪的错误,如果您不引用System.Web.Mvc.Html,那么它会说找不到DropDownListFor,但它也无法解决它。您必须手动执行using System.Web.Mvc.Html;。你知道的。
    • 我在一个 gist 中有一个变体,我们在所有项目中都使用它:gist.github.com/1287511
    • 很好的解决方案,谢谢,如果你能缓存GetEnumDescription的结果就更好了
    • 新的 MVC 5.1 EnumDropDownListFor 不使用 [Description("")] 但它使用 [Display(Name = "")]!享受:)
    【解决方案3】:

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

    型号

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

    查看

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

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

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

    【讨论】:

    • 您应该创建一个特定于 MVC 5.1 的新问题并将其作为答案,然后给我发送一个帖子链接,以便我可以为最喜欢的人投票。
    • 我不喜欢 EnumDropDownListFor() 的地方在于它将枚举的 int 值而不是文本保存到数据库中,因此如果您选择添加新的枚举项,它必须必须放在列表的末尾,以免失去保存的数据库 int 值与枚举项的原始位置的关系。如果保存文本,这是不必要的限制。另外,我宁愿能够查看数据库并查看文本,而不是整数,然后我必须在其他地方查找文本值。否则这个 html helper 使用起来非常方便。
    • @Giovanni - 您可以指定自己的数值。
    • 它还没有结束枚举 [Flags] :(
    • @Giovanni Strict 设计应该为每个枚举条目分配值(如果它很重要),否则该值无关紧要(因此将新条目放在最后应该不是问题)。在节省存储空间和提高性能(执行某些搜索时)方面,保存 int 值会更好。
    【解决方案4】:

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

    原来 C#3 等使这变得非常容易。我有一个enum,叫做TaskStatus

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

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

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

    匿名类型和 LINQ 使这更加优雅恕我直言。无意冒犯,阿什。 :)

    【讨论】:

    • 好答案!我希望有人会使用 linq 和 SelectList :) 很高兴我先检查了这里!
    • ID = s 给我 DataTextField 不是值?可能是什么原因?谢谢
    • Rune,我使用了相同的方法,并且 DropDownList 确实呈现,但当它发布到服务器时,它不会保存我选择的值。
    • @BarbarosAlp 要使 ID 成为数字,您需要将枚举转换为 int:select new { ID = (int)s, Name = s.ToString() };
    • 这是我最喜欢的答案,因为它很简单。遗憾的是,由于所选答案使用了您的解决方案,您没有获得足够的积分。
    【解决方案5】:

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

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

    说这里是你的模型:

    示例用法:

    生成的用户界面:

    并生成HTML

    助手扩展源代码快照:

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

    编辑:这是代码:

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

    【讨论】:

    • 只是我的意见,但我认为这个答案比公认的答案要干净得多。我特别喜欢使用 Description 属性的选项。我添加了代码,以便人们无需下载即可复制/粘贴。
    • 调用扩展方法为 EnumDropDownListFor 而不是 DropDownListFor 用法:-> @Html.EnumDropDownListFor(x => x.Gender)
    • 对于寻找添加更多元素的人 "请选择" return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected,firstElement),"Please Select");
    • 工作正常!但是,在详细信息页面上,DisplayFor() 显示枚举的选定值而不是相应的描述。我想这需要枚举类型的 DisplayFor() 重载。有人有解决方案吗?
    • +100 万对图形的赞誉
    【解决方案6】:

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

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

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

    此外,您实际上不需要泛化扩展方法,因为您可以使用 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();
        }
    }
    

    【讨论】:

    • 对我不起作用('System.NullReferenceException:对象引用未设置为对象的实例。')...我的“模型”为空...可能有事可做带有西蒙包含的“GetNonNullableModelType”
    • @Cristi,您是对的,此解决方案不适用于您的模型为空的情况。我尽量避免这样的设计,并在这种情况下初始化为“空”模型。
    • 好吧,我是 asp mvc 的新手,但我在 .Net 方面很有经验。谢谢,我会调查你的建议。顺便说一句,您的 ToDescription 扩展远远超出了“枚举”范围。我想“对象”本身很好。这是我拿西蒙的代码并对其进行更多清理时使用的。
    • @Cristi 很难理解您所说的“远远超出 'Enum' 范围”是什么意思,但听起来您是在说 ToDescription 扩展方法不是对 ItemTypes 枚举的强类型?这是有意的,并且使扩展方法一般可被所有枚举使用。如果您将其与通用扩展方法进行比较,那么每种方法都各有利弊。特别是,如果您进行泛型化,则不能仅将其限制在枚举上。
    • 太好了,谢谢。如果没有描述,我更改了 value.ToString 以使用扩展 FromCamelCase。这就是我滚动的方式:)
    【解决方案7】:

    如果您正在寻找简单易用的功能,那么没有扩展功能..这就是我所做的

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

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

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

    【讨论】:

    • 很好,这可以填充下拉列表,但是如何在 Razor 语法中为 Html.DropDownListFor 设置默认选定值?我想显示一个带有枚举组合框的表格,我还需要根据之前的值设置选定的值。
    • 应该能够将带有所选值的第二个参数传递给新的 SelectList(IEnumerable,object) 函数。 MSDN 文档:msdn.microsoft.com/en-us/library/dd460123.aspx
    【解决方案8】:

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

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

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

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

    【讨论】:

    • 谢谢!这是我需要的答案。我将 Enum 的整数值作为列存储在数据库中,这个解决方案似乎运行良好。
    • 但是如果您存储的是 char 而不是 int 怎么办?这是我的情况。显然,我可以将 (int) 更改为 (char),但如何也将其设为通用。该怎么做?
    • @Stefandvds 关于转换为正确的表示类型,这是一个很好的问题。根据我刚刚执行的测试,您似乎能够实现这一目标的唯一方法是将实际类型指定为另一个类型参数。 ToSelectList&lt;TEnum, TEnumValue&gt;(this TEnum enumObj) { ... }
    • @Stefandvds See this question.
    • 如果你的枚举值是int,你可以简单地使用Value = Convert.ToInt32(e)(int)e 无法编译。 :(
    【解决方案9】:

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

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

    【讨论】:

    • 这就是我一直在寻找的东西,虽然它比我想象的要丑陋。我想知道为什么 Visual Studio 不允许你直接将 e 转换为 int
    • 或者你可以简单地使用ID = Convert.ToInt32(e)
    【解决方案10】:

    完成这项工作的一个超级简单的方法 - 没有所有看起来过分的扩展内容:

    你的枚举:

        public enum SelectedLevel
        {
           Level1,
           Level2,
           Level3,
           Level4
        }
    

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

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

    然后将其放入 ViewBag:

        ViewBag.RequiredLevel = new SelectList(myLevels);
    

    最后简单的将它绑定到 View:

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

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

    更新:请参阅下面的 Andrews 评论。

    【讨论】:

    • 这仅在您没有为枚举分配任何值时才有效。如果您有Level1 = 1,那么下拉列表的值将是"Level1" 而不是1
    【解决方案11】:

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

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

    【讨论】:

    • 或者使用标签助手&lt;select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList&lt;MyEnum&gt;()"&gt;&lt;/select&gt;
    • 是的,我说标签助手更好,因为格式更接近纯 HTML ;)
    • 你也可以这样做@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList(typeof(FooEnum)))
    • 简单可爱。泰!
    • 很棒的答案。希望不必创建自定义方法来执行此操作
    【解决方案12】:

    我为此找到的最佳解决方案是将this blogSimon Goldstone's answer 结合使用。

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

    然后使用 [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; }
    }
    

    查看:

    @using MyProject.Extensions
    {
    //...
        @Html.EnumDropDownListFor(model => model.CuriousQuestion)
    //...
    }
    

    扩展名(直接来自Simon Goldstone's answer,为了完整起见包含在此处):

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

    【讨论】:

    • 这不起作用,MVC 4 Razor。在视图或运行时,error = "以下方法或属性之间的调用不明确 'LDN.Extensions.MvcExtensions.EnumDropDownListFor(System.Web.Mvc.HtmlHelper, System .Linq.Expressions.Expression>)' 和....” 并且再次重复使用相同道具的完全相同的方法(此处允许的字符数不足)。
    【解决方案13】:
    @Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
    

    【讨论】:

    • 好!如何以这种方式从枚举中获取值和文本?我的意思是我有 SomeEnum { some1 = 1, some2 = 2} 我需要为选择列表的文本获取数字 (1, 2) 和文本 (some1, some2)
    【解决方案14】:

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

    【讨论】:

      【解决方案15】:

      现在通过@Html.EnumDropDownListFor()@Html.EnumDropDownListFor()在 MVC 5.1 中开箱即用地支持此功能

      查看以下链接:

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

      根据上面的投票,微软花了 5 年时间才实现了这样一个非常需要的功能,真是太可惜了!

      【讨论】:

        【解决方案16】:

        这是符文和奖品答案,已更改为使用枚举 int 值作为 ID。

        示例枚举:

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

        扩展方法:

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

        使用示例:

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

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

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

        生成的 HTML 示例:

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

        请注意,您用来调用ToSelectList 的项目是选定项目。

        【讨论】:

        • 或者你可以简单地使用Id = Convert.ToInt32(e)
        【解决方案17】:

        这是 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)
        

        【讨论】:

        • 只有当您的枚举由以 0 开头的连续值组成时才有效。Flags 枚举不适用于此。不过,创造性地使用了索引 Select。
        【解决方案18】:

        基于 Simon 的回答,类似的方法是从资源文件中获取 Enum 值以显示,而不是在 Enum 本身的描述属性中显示。如果您的网站需要以一种以上的语言呈现,并且如果您要为 Enums 提供特定的资源文件,这将很有帮助,您可以更进一步,在您的 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();
        }
        

        Enums.Resx 文件中的资源看起来像 ItemTypes_Movie : 电影

        我喜欢做的另一件事是,与其直接调用扩展方法,我宁愿使用@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))
        }
        

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

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

        【讨论】:

          【解决方案19】:

          好吧,我真的迟到了,但值得一提的是,我已经在博客上写了这个主题,我创建了一个 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);
          

          在你看来:

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

          助手类:

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

          【讨论】:

            【解决方案20】:

            我在这方面已经很晚了,但我刚刚找到了一种非常酷的方法,只需一行代码,如果您愿意添加 Unconstrained Melody NuGet 包(Jon Skeet 的一个不错的小型库)。

            这个解决方案更好,因为:

            1. 它确保(使用泛型类型约束)该值确实是一个枚举值(由于 Unconstrained Melody)
            2. 它避免了不必要的拳击(由于 Unconstrained Melody)
            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() });
                  }
              }
              

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

            【讨论】:

            • +1 用于使用 Jon Skeet 的代码 :),不过只是在开玩笑
            【解决方案21】:

            我找到了答案here。但是,我的一些枚举具有[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
                        );
                }
            

            希望对您有所帮助。

            【讨论】:

            • 我想返回一个 type = DropdownList 的成员。我对 Text = DescriptionAttribute 很满意,但发现很难从 Value 中获取 int 值
            【解决方案22】:

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

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

            【讨论】:

              【解决方案23】:

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

              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) 是你要加载的资源,然后你会得到本地化的字符串,如果你的枚举器有多个单词的值,这也很有用。

              【讨论】:

                【解决方案24】:

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

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

                取而代之的是:

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

                这里是:

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

                【讨论】:

                  【解决方案25】:

                  您也可以在 Griffin.MvcContrib 中使用我的自定义 HtmlHelpers。以下代码:

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

                  生成:

                  https://github.com/jgauffin/griffin.mvccontrib

                  【讨论】:

                    【解决方案26】:
                    @Html.DropdownListFor(model=model->Gender,new List<SelectListItem>
                    {
                     new ListItem{Text="Male",Value="Male"},
                     new ListItem{Text="Female",Value="Female"},
                     new ListItem{Text="--- Select -----",Value="-----Select ----"}
                    }
                    )
                    

                    【讨论】:

                      【解决方案27】:

                      我想以不同的方式回答这个问题,用户无需在controllerLinq 表达式中执行任何操作。这样……

                      我有一个ENUM

                      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

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

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

                      如果你想选择一个索引,那么试试这个

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

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

                      【讨论】:

                        【解决方案28】:

                        @Simon Goldstone:感谢您的解决方案,它可以完美地应用于我的案例。唯一的问题是我必须将它翻译成 VB。但是现在它已经完成并且为了节省其他人的时间(以防他们需要它)我把它放在这里:

                        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
                        

                        结束你这样使用它:

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

                        【讨论】:

                          【解决方案29】:

                          我最终创建了扩展方法来做这里基本上是接受答案的事情。 Gist 的后半部分专门针对 Enum。

                          https://gist.github.com/3813767

                          【讨论】:

                            【解决方案30】:
                            @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" }
                            
                            })
                            

                            【讨论】:

                            • 我认为这不是一个有效的答案,它根本没有使用枚举来填充下拉列表。
                            猜你喜欢
                            • 2016-08-22
                            • 1970-01-01
                            • 2022-11-21
                            • 2010-09-08
                            • 2013-08-26
                            相关资源
                            最近更新 更多