首页 文章

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

提问于
浏览
606

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

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

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

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

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

30 回答

  • 177
    @Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
    
  • 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)
    

    希望这对你有所帮助!

    **编辑2014-JAN-23:微软刚刚发布了MVC 5.1,它现在有一个EnumDropDownListFor功能 . 遗憾的是它似乎不尊重[Description]属性,因此上面的代码仍然有效 . 参见Enum section in Microsoft的MVC 5.1发行说明 .

    Update: It does support the Display attribute [Display(Name = "Sample")] though, so one can use that.

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

  • 1

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

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

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

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

  • 3

    基于Simon的答案,类似的方法是从资源文件中获取Enum值,而不是在Enum本身的描述属性中显示 . 如果您的站点需要使用多种语言进行呈现,并且如果您要为Enums创建特定的资源文件,那么这将非常有用,您可以更进一步,在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: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))
    }
    

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

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

  • 56

    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)
    

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

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

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

    你的枚举:

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

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

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

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

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

  • 1

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

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

    这里说的是你的型号:

    enter image description here

    Sample Usage:

    enter image description here

    Generated UI:
    enter image description here

    And generated HTML

    enter image description here

    The Helper Extension Source Code snap shot:

    enter image description here

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

    编辑:这是代码:

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

    扩展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对象 .

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

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

  • 3

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

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

    使用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);
    }
    
  • 4

    @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))
    
  • 8

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

    这是我的帮助方法版本 . 我用这个:

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

    这里有一个Martin Faartoft变体,您可以在其中放置自定义标签,非常适合本地化 .

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

    在视图中使用:

    @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)
    
  • 9
    @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" }
    
    })
    
  • 1

    你想看看像Enum.GetValues这样的东西

  • 7

    这是Rune&Prize答案被更改为使用Enum 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()) %>
    

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

    <%@ 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 的项目是所选项目 .

  • 2

    如果要添加本地化支持,只需将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)是您要加载的资源,然后您获得本地化的String,如果您的枚举器具有包含多个单词的值,这也很有用 .

  • 31

    我找到的最佳解决方案是将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);
            }
        }
    }
    
  • 46

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

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

    产生:

    enter image description here

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

  • 2

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

    检查以下链接:

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

    真是遗憾的是,根据上述投票,微软用了5年的时间来实现这样的功能需求!

  • 123

    好吧,我真的很晚才参加派对,但是为了它的 Value ,我在博客上写了这个主题,我创建了一个 EnumHelper 类,可以很容易地进行转换 .

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

    In your controller:

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

    In your View:

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

    The helper class:

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

    我找到了答案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
                );
        }
    

    希望有所帮助 .

  • 344
    @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 ----"}
    }
    )
    
  • 760

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

    原来C#3等让这很容易 . 我有一个名为 TaskStatusenum

    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使这个更优雅的恕我直言 . Ash,没有违法行为 . :)

  • 1

    我做了以下工作并成功运作:

    • 在view.cshtml中:

    @model MyModel.cs

    @Html.EnumDropDownListFor(m=>m.MyItemType )
    
    • 在Model:MyModel.cs中

    public ItemTypes MyItemType {get;组; }

  • 2

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

    by using MyApp.Common

  • 5

    我最终创建了扩展方法来完成本质上接受的答案 . Gist的后半部分专门针对Enum .

    https://gist.github.com/3813767

  • 9

    我在这个问题上已经很晚了,但是如果您乐意添加Unconstrained Melody NuGet包(Jon Skeet的一个漂亮的小型库),我发现用一行代码就可以找到一个非常酷的方法 .

    此解决方案更好,因为:

    • 它确保(使用泛型类型约束)该值实际上是枚举值(由于Unconstrained Melody)

    • 它避免了不必要的拳击(由于无约束的旋律)

    • 它缓存所有描述以避免在每次调用时使用反射(由于Unconstrained Melody)

    • 它的代码少于其他解决方案!

    所以,这是让这个工作的步骤:

    • 在包管理器控制台中,"Install-Package UnconstrainedMelody"

    • 在模型上添加属性,如下所示:

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

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

  • 4

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

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

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

相关问题