简体   繁体   English

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

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

I'm trying to use the Html.DropDownList extension method but can't figure out how to use it with an enumeration.我正在尝试使用Html.DropDownList扩展方法,但无法弄清楚如何将它与枚举一起使用。

Let's say I have an enumeration like this:假设我有一个这样的枚举:

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

How do I go about creating a dropdown with these values using the Html.DropDownList extension method?如何使用Html.DropDownList扩展方法使用这些值创建下拉列表?

Or is my best bet to simply create a for loop and create the Html elements manually?或者我最好的选择是简单地创建一个 for 循环并手动创建 Html 元素?

For MVC v5.1 use Html.EnumDropDownListFor对于 MVC v5.1 使用 Html.EnumDropDownListFor

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

For MVC v5 use EnumHelper对于 MVC v5 使用 EnumHelper

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

For MVC 5 and lower对于 MVC 5 及更低版本

I rolled Rune's answer into an extension method:我将 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);
        }
    }
}

This allows you to write:这允许您编写:

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

by using MyApp.Common通过using MyApp.Common

I know I'm late to the party on this, but thought you might find this variant useful, as this one also allows you to use descriptive strings rather than enumeration constants in the drop down.我知道我迟到了,但我认为您可能会发现这个变体很有用,因为这个变体还允许您在下拉列表中使用描述性字符串而不是枚举常量。 To do this, decorate each enumeration entry with a [System.ComponentModel.Description] attribute.为此,请使用 [System.ComponentModel.Description] 属性修饰每个枚举条目。

For example:例如:

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

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

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

Here is my code:这是我的代码:

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

You can then do this in your view:然后,您可以在您的视图中执行此操作:

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

Hope this helps you!希望这对你有帮助!

**EDIT 2014-JAN-23: Microsoft have just released MVC 5.1, which now has an EnumDropDownListFor feature. **EDIT 2014-JAN-23:Microsoft 刚刚发布了 MVC 5.1,它现在具有 EnumDropDownListFor 功能。 Sadly it does not appear to respect the [Description] attribute so the code above still stands.See Enum section in Microsoft's release notes for MVC 5.1.遗憾的是,它似乎不尊重 [Description] 属性,因此上面的代码仍然有效。请参阅 Microsoft MVC 5.1 发行说明中的Enum 部分

Update: It does support the Display attribute [Display(Name = "Sample")] though, so one can use that.更新:它确实支持Display属性[Display(Name = "Sample")] ,所以可以使用它。

[Update - just noticed this, and the code looks like an extended version of the code here: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/ , with a couple of additions. [更新 - 刚刚注意到这一点,代码看起来像这里代码的扩展版本: https : //blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- dropdownlist-helper-for-enums/ ,添加了一些内容。 If so, attribution would seem fair ;-)]如果是这样,归属似乎是公平的;-)]

In ASP.NET MVC 5.1 , they added the EnumDropDownListFor() helper, so no need for custom extensions:ASP.NET MVC 5.1 中,他们添加了EnumDropDownListFor()助手,因此不需要自定义扩展:

Model :型号:

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

View :查看

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

Using Tag Helper (ASP.NET MVC 6) :使用标签助手(ASP.NET MVC 6)

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

I bumped into the same problem, found this question, and thought that the solution provided by Ash wasn't what I was looking for;碰到了同样的问题,发现了这个问题,觉得Ash提供的解决方案不是我想要的; Having to create the HTML myself means less flexibility compared to the built-in Html.DropDownList() function.与内置的Html.DropDownList()函数相比,必须自己创建 HTML 意味着更少的灵活性。

Turns out C#3 etc. makes this pretty easy.原来 C#3 等使这很容易。 I have an enum called TaskStatus :我有一个名为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);

This creates a good ol' SelectList that can be used like you're used to in the view:这将创建一个很好的 ol' SelectList ,可以像在视图中一样使用:

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

The anonymous type and LINQ makes this so much more elegant IMHO.匿名类型和 LINQ 使这更加优雅恕我直言。 No offence intended, Ash.无意冒犯,阿什。 :) :)

Here is a better encapsulated solution:这是一个更好的封装解决方案:

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

Say here is your model:说这是你的模型:

在此处输入图片说明

Sample Usage:示例用法:

在此处输入图片说明

Generated UI:生成的用户界面:在此处输入图片说明

And generated HTML并生成 HTML

在此处输入图片说明

The Helper Extension Source Code snap shot: Helper 扩展源代码快照:

在此处输入图片说明

You can download the sample project from the link I provided.您可以从我提供的链接下载示例项目。

EDIT: Here's the code:编辑:这是代码:

public static class EnumEditorHtmlHelper
{
    /// <summary>
    /// Creates the DropDown List (HTML Select Element) from LINQ 
    /// Expression where the expression returns an Enum type.
    /// </summary>
    /// <typeparam name="TModel">The type of the model.</typeparam>
    /// <typeparam name="TProperty">The type of the property.</typeparam>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <param name="expression">The expression.</param>
    /// <returns></returns>
    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression) 
        where TModel : class
    {
        TProperty value = htmlHelper.ViewData.Model == null 
            ? default(TProperty) 
            : expression.Compile()(htmlHelper.ViewData.Model);
        string selected = value == null ? String.Empty : value.ToString();
        return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected));
    }

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

Html.DropDownListFor only requires an IEnumerable, so an alternative to Prise's solution is as follows. Html.DropDownListFor 只需要一个 IEnumerable,因此 Prise 解决方案的替代方案如下。 This will allow you to simply write:这将允许您简单地编写:

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

[Where SelectedItemType is a field on your model of type ItemTypes, and your model is non-null] [其中 SelectedItemType 是您模型中 ItemTypes 类型的字段,并且您的模型非空]

Also, you don't really need to genericize the extension method as you can use enumValue.GetType() rather than typeof(T).此外,您实际上并不需要泛化扩展方法,因为您可以使用 enumValue.GetType() 而不是 typeof(T)。

EDIT: Integrated Simon's solution here as well, and included ToDescription extension method.编辑:此处也集成了 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();
    }
}

So without Extension functions if you are looking for simple and easy.. This is what I did因此,如果您正在寻找简单易用的功能,则无需扩展功能..这就是我所做的

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

where XXXXX.Sites.YYYY.Models.State is an enum其中 XXXXX.Sites.YYYY.Models.State 是一个枚举

Probably better to do helper function, but when time is short this will get the job done.做辅助功能可能更好,但是当时间很短时,这将完成工作。

Expanding on Prise and Rune's answers, if you'd like to have the value attribute of your select list items map to the integer value of the Enumeration type, rather than the string value, use the following code:扩展 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);
}

Instead of treating each Enumeration value as a TEnum object, we can treat it as a object and then cast it to integer to get the unboxed value.我们可以将每个 Enumeration 值视为一个 TEnum 对象,而不是将其视为一个对象,然后将其转换为整数以获取未装箱的值。

Note: I also added a generic type constraint to restrict the types for which this extension is available to only structs (Enum's base type), and a run-time type validation which ensures that the struct passed in is indeed an Enum.注意:我还添加了一个泛型类型约束,以限制此扩展仅适用于结构(Enum 的基类型)的类型,以及确保传入的结构确实是 Enum 的运行时类型验证。

Update 10/23/12: Added generic type parameter for underlying type and fixed non-compilation issue affecting .NET 4+. 2012 年 10 月 23 日更新:为基础类型添加了泛型类型参数,并修复了影响 .NET 4+ 的非编译问题。

A super easy way to get this done - without all the extension stuff that seems overkill is this:完成此操作的一种超级简单的方法 - 没有所有看似矫枉过正的扩展内容是这样的:

Your enum:你的枚举:

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

Inside of your controller bind the Enum to a List:在您的控制器内部将 Enum 绑定到一个列表:

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

After that throw it into a ViewBag:之后将其放入 ViewBag 中:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Finally simply bind it to the View:最后简单地将它绑定到视图:

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

This is by far the easiest way I found and does not require any extensions or anything that crazy.这是迄今为止我发现的最简单的方法,不需要任何扩展或任何疯狂的东西。

UPDATE : See Andrews comment below.更新:请参阅下面的安德鲁斯评论。

To solve the problem of getting the number instead of text using Prise's extension method.解决使用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);
}

The best solution I found for this was combining this blog with Simon Goldstone's answer .我为此找到的最佳解决方案是将此博客Simon Goldstone 的答案相结合。

This allows use of the enum in the model.这允许在模型中使用枚举。 Essentially the idea is to use an integer property as well as the enum, and emulate the integer property.本质上的想法是使用整数属性以及枚举,并模拟整数属性。

Then use the [System.ComponentModel.Description] attribute for annotating the model with your display text, and use an "EnumDropDownListFor" extension in your view.然后使用 [System.ComponentModel.Description] 属性用您的显示文本注释模型,并在您的视图中使用“EnumDropDownListFor”扩展。

This makes both the view and model very readable and maintainable.这使得视图和模型都非常可读和可维护。

Model:模型:

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

View:看法:

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

Extension (directly from Simon Goldstone's answer , included here for completeness):扩展(直接来自西蒙戈德斯通的回答,为了完整起见,这里包括):

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

你想看看使用像Enum.GetValues

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

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

This is Rune & Prise answers altered to use the Enum int value as the ID.这是 Rune & Prize 答案更改为使用 Enum int值作为 ID。

Sample Enum:示例枚举:

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

Extension method:扩展方法:

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

Sample of usage:使用示例:

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

Remember to Import the namespace containing the Extension method记得导入包含扩展方法的命名空间

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

Sample of generated HTML:生成的 HTML 示例:

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

Note that the item that you use to call the ToSelectList on is the selected item.请注意,您用来调用ToSelectList的项目是所选项目。

Now this feature is supported out-of-the-box in MVC 5.1 through @Html.EnumDropDownListFor()现在,此功能在 MVC 5.1 中通过@Html.EnumDropDownListFor()支持开箱即用

Check the following link:检查以下链接:

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

It is really shame that it took Microsoft 5 years to implement such as feature which is so in demand according to the voting above!根据上面的投票结果,微软花了 5 年时间才实现了如此受欢迎的功能,这真是太可惜了!

This is version for Razor:这是 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)

Building on Simon's answer, a similar approach is to get the Enum values to display from a Resource file, instead of in a description attribute within the Enum itself.基于 Simon 的回答,类似的方法是从 Resource 文件中获取要显示的 Enum 值,而不是在 Enum 本身的描述属性中显示。 This is helpful if your site needs to be rendered in more than one language and if you were to have a specific resource file for Enums, you could go one step further and have just Enum values, in your Enum and reference them from the extension by a convention such as [EnumName]_[EnumValue] - ultimately less typing!如果您的网站需要以一种以上的语言呈现,并且如果您要为 Enum 提供特定的资源文件,则这很有用诸如 [EnumName]_[EnumValue] 之类的约定 - 最终减少输入!

The extension then looks like:扩展看起来像:

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

Resources in the Enums.Resx file looking like ItemTypes_Movie : Film Enums.Resx 文件中的资源类似于 ItemTypes_Movie : Film

One other thing I like to do is, instead of calling the extension method directly, I'd rather call it with a @Html.EditorFor(x => x.MyProperty), or ideally just have the whole form, in one neat @Html.EditorForModel().我喜欢做的另一件事是,我宁愿用@Html.EditorFor(x => x.MyProperty) 来调用它,而不是直接调用扩展方法,或者理想情况下只是拥有整个表单,以一个整洁的@ Html.EditorForModel()。 To do this I change the string template to look like this为此,我将字符串模板更改为如下所示

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

If this interests you, I've put a much more detailed answer here on my blog:如果您对此感兴趣,我在我的博客上提供了更详细的答案:

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

Well I'm really late to the party, but for what it is worth, I have blogged about this very subject whereby I create a EnumHelper class that enables very easy transformation.好吧,我参加派对真的很晚,但就其价值而言,我已经写了一篇关于这个主题的博客,我创建了一个EnumHelper类,可以非常轻松地进行转换。

http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23 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() });
    }
}

I am very late on this one but I just found a really cool way to do this with one line of code, if you are happy to add the Unconstrained Melody NuGet package (a nice, small library from Jon Skeet).我在这方面很晚,但我刚刚找到了一种非常酷的方法,可以用一行代码来做到这一点,如果您愿意添加不受约束的旋律NuGet 包(来自 Jon Skeet 的一个不错的小型库)。

This solution is better because:此解决方案更好,因为:

  1. It ensures (with generic type constraints) that the value really is an enum value (due to Unconstrained Melody)它确保(具有泛型类型约束)该值确实是一个枚举值(由于不受约束的旋律)
  2. It avoids unnecessary boxing (due to Unconstrained Melody)它避免了不必要的拳击(由于不受约束的旋律)
  3. It caches all the descriptions to avoid using reflection on every call (due to Unconstrained Melody)它缓存所有描述以避免在每次调用时使用反射(由于不受约束的旋律)
  4. It is less code than the other solutions!它的代码比其他解决方案少!

So, here are the steps to get this working:所以,这里是让这个工作的步骤:

  1. In Package Manager Console, "Install-Package UnconstrainedMelody"在包管理器控制台中,“安装包不受约束的旋律”
  2. Add a property on your model like so:在您的模型上添加一个属性,如下所示:

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

Now that you have the List of SelectListItem exposed on your model, you can use the @Html.DropDownList or @Html.DropDownListFor using this property as the source.现在您已经在模型上公开了 SelectListItem 列表,您可以使用 @Html.DropDownList 或 @Html.DropDownListFor 使用此属性作为源。

I found an answer here .我在这里找到了答案。 However, some of my enums have [Description(...)] attribute, so I've modified the code to provide support for that:但是,我的一些枚举具有[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
            );
    }

Hope that helps.希望有帮助。

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

Another fix to this extension method - the current version didn't select the enum's current value.对此扩展方法的另一个修复 - 当前版本没有选择枚举的当前值。 I fixed the last line:我修复了最后一行:

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

If you want to add localization support just change the s.toString() method to something like this:如果您想添加本地化支持,只需将 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()) };

In here the typeof(Resources) is the resource you want to load, and then you get the localized String, also useful if your enumerator has values with multiple words.在这里 typeof(Resources) 是您要加载的资源,然后您将获得本地化的字符串,如果您的枚举器具有多个单词的值,这也很有用。

This is my version of helper method.这是我的辅助方法版本。 I use this:我用这个:

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

Instead of that:取而代之的是:

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

Here it is:这里是:

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

I would like to answer this question in a different way where, user need not to do anything in controller or Linq expression.我想以不同的方式回答这个问题,用户不需要在controllerLinq表达式中做任何事情。 This way...这边走...

I have a ENUM我有一个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*/
    }

Now I canto simply create a dropdown by using this enum .现在我可以使用这个enum简单地创建一个dropdown

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

OR或者

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

If you want to make a index selected then try this如果你想选择一个索引然后试试这个

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

Here I have used AccessLevelEnum.NoAccess as an extra parameter for default selecting the dropdown.在这里,我使用AccessLevelEnum.NoAccess作为默认选择下拉列表的额外参数。

You can also use my custom HtmlHelpers in Griffin.MvcContrib.您还可以在 Griffin.MvcContrib 中使用我的自定义 HtmlHelpers。 The following code:以下代码:

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

Generates:产生:

在此处输入图片说明

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

I ended up creating extention methods to do what is essentially the accept answer here.我最终创建了扩展方法来做这里基本上是接受答案的事情。 The last half of the Gist deals with Enum specifically. Gist 的后半部分专门处理 Enum。

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

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

})

@Simon Goldstone: Thanks for your solution, it can be perfectly applied in my case. @Simon Goldstone:感谢您的解决方案,它可以完美地应用于我的情况。 The only problem is I had to translate it to VB.唯一的问题是我必须将它翻译成 VB。 But now it is done and to save other people's time (in case they need it) I put it here:但现在已经完成并节省其他人的时间(以防他们需要它)我把它放在这里:

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

End You use it like this:你这样使用它:

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

Here a Martin Faartoft variation where you can put custom labels which is nice for localization. 这是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);
    }
}

Use in view: 在视图中使用:

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

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

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