asp.net - ASP.NET MVC如何从enum创建一个dropdownlist?

  显示原文与译文双语对照的内容

我正试图使用 Html.DropDownList 扩展方法,但不知道如何在枚举中使用它。

假设我有这样一个枚举:


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

如何使用 Html.DropDownList 扩展方法创建具有这些值的下拉列表? 还是我最好是创建一个循环来手动创建html元素?

时间:

编辑:MVC 5已经添加了 EnumHelper


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


我把符文的回答变成了一个扩展方法:


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

在水滴down,中我知道我是没有赶上了队伍在这,但是想着你应该会发现这种操作类型有用,就像这个例子还允许你使用描述性的字符串( 而不是枚举间能进行 为此,使用 [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] 属性,因此上面的代码仍然存在。 ( 请参见 http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum 。txt以发布微软便笺。)

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

[ 更新- 刚刚注意到这个,代码看起来像代码的扩展版本: http://blogs.msdn.com/b/stuartleeks/archive/1 2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums. aspx,带有几个附加内容。 如果是的话,属性似乎公平;- )

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

C#3 等等 使得这相当容易。 我有一个名为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);

这将创建一个很好的ol selectlist,可以像在视图中使用的那样使用:


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

匿名类型和LINQ使得这变得更加优雅。 无意冒犯,Ash 。

ASP.NET MVC 5.1 中,他们添加了 EnumDropDownListFor() helper,无需自定义 extenions:

:模型


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

查看:


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

Html.DropDownListFor 只需要一个 IEnumerable,所以替代解决方案的方法如下。 这将允许你简单地编写:


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

另外,你并不真正需要的扩展方法为你可以使用 enumValue.GetType() genericize而不是 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();
 }
}

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

http://www.spicelogic.com/Journal/ASP-NET-MVC-DropDownListFor-Html-Helper-Enum-5

下面是你的模型:

enter image description here

使用了示例:

enter image description here

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

和生成的HTML

enter image description here

helper 扩展的源代码的快拍:

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

所以没有扩展函数,如果你正在寻找简单简单的。 这就是我做


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

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

最好是做 helper 函数,但当时间太短时,这将会完成任务。

如果你想要将选择列表项的值属性映射到枚举类型的整数值,而不是字符串值,则展开符号和答案,使用以下代码:


public static SelectList ToSelectList<T, TU>(T enumObj) 
 where T : struct
 where TU : struct
{
 if(!typeof(T).IsEnum) throw new ArgumentException("Enum is required.","enumObj");

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

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

我们可以将每个枚举值当作一个TEnum对象对待,然后将它的转换成整数,然后将它的转换成整数以得到未装箱的值。

在的确是一种 enum, 注意: 我还添加了一个泛型类型约束来限制这个扩展只可以用于为它的的类型结构( 枚举类型)的基础,和一个run-time类型验证该结构,用以确保 passed.

更新 10/23/12: 为基础类型添加了泛型类型参数和影响. NET 4 +的固定non-compilation问题。

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

西门关系对 goldstone, 最佳的解决方案这个博客我找到了这个问题的方法是结合 .

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

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

这使得视图和模型既可以读又可以维护。

模型:


public enum YesPartialNoEnum
{
 [Description("Yes")]
 Yes,
 [Description("Still undecided")]
 Partial,
 [Description("No")]
 No
}

//........

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

视图:


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

扩展( 直接从的goldstone 回答,包括在这里,用于完整):


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;

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

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

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

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

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

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

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

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

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

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

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

...