如何从ASP.NET MVC中的枚举创build一个下拉列表?
我试图使用Html.DropDownList
扩展方法,但无法弄清楚如何使用枚举。
比方说,我有这样的枚举:
public enum ItemTypes { Movie = 1, Game = 2, Book = 3 }
我该如何使用Html.DropDownList
扩展方法来创build具有这些值的下拉菜单?
或者,我最好只是简单地创build一个for循环并手动创buildHtml元素?
对于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和更低
我把符文的答案翻译成扩展方法:
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
我知道我对这个派对迟到了,但是认为你可能会发现这个变体是有用的,因为这个也允许你在下拉列表中使用描述性string而不是枚举常量。 为此,请使用[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年1月23日:微软刚刚发布MVC 5.1,现在有一个EnumDropDownListForfunction。 可悲的是,它似乎没有尊重[Description]属性,所以上面的代码仍然存在。 (有关 Microsoft发行说明, 请参阅http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum 。)
更新:虽然支持Display属性[Display(Name = "Sample")]
,所以可以使用它。
[更新 – 只是注意到了这一点,代码看起来像一个扩展版本的代码在这里: http : //blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating- a-dropdownlist-helper-for-enums.aspx ,还有一些补充。 如果是这样,归因会看起来公平;-)]
在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>()">
我遇到了同样的问题,发现了这个问题,并认为Ash提供的解决scheme并不是我所期待的。 与内置的Html.DropDownList()
函数相比,自己创buildHTML意味着更less的灵活性。
原来C#3等,这很容易。 我有一个名为TaskStatus
的enum
:
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);
这创build了一个很好的SelectList
,可以像你习惯的那样在视图中使用:
<td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr>
匿名types和LINQ使这个更加优雅恕我直言。 Ash没有任何意图。 🙂
这是一个更好的封装解决scheme:
http://www.spicelogic.com/Journal/ASP-NET-MVC-DropDownListFor-Html-Helper-Enum-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(); } }
Html.DropDownListFor只需要一个IEnumerable,所以Prize的解决scheme的替代方法如下。 这将允许你简单地写:
@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())
[其中SelectedItemType是您的模型typesItemTypes上的字段,并且您的模型是非空]
此外,您不需要泛化扩展方法,因为您可以使用enumValue.GetType()而不是typeof(T)。
编辑:西蒙的综合解决scheme,以及包括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(); } }
所以没有扩展function,如果你正在寻找简单和容易..这是我做的
<%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>
其中XXXXX.Sites.YYYY.Models.State是一个枚举
可能更好的帮助function,但时间短,这将完成工作。
如果您希望将select列表项的值属性映射到枚举types的整数值而不是string值,请使用以下代码扩展奖和符文的答案:
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对象,而不是将其视为一个对象,然后将其转换为整数以获得取消装箱值。
注意:我还添加了一个genericstypes约束来限制只有结构体(Enum的基types)可以使用这个扩展的types,以及确保传入的结构体确实是一个Enum的运行时typesvalidation。
2012年12月23日更新:为基础types添加了genericstypes参数,并修正了影响.NET 4+的非编译问题。
用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); }
我find的最好的解决办法是把这个博客与Simon Goldstone的答案结合起来。
这允许在模型中使用枚举。 基本上这个想法是使用整数属性以及枚举,并模拟整数属性。
然后使用[System.ComponentModel.Description]属性为显示文本注释模型,并在视图中使用“EnumDropDownListFor”扩展名。
这使得视图和模型都非常可读和可维护。
模型:
public enum YesPartialNoEnum { [Description("Yes")] Yes, [Description("Still undecided")] Partial, [Description("No")] No } //........ [Display(Name = "The label for my dropdown list")] public virtual Nullable<YesPartialNoEnum> CuriousQuestion{ get; set; } public virtual Nullable<int> CuriousQuestionId { get { return (Nullable<int>)CuriousQuestion; } set { CuriousQuestion = (Nullable<YesPartialNoEnum>)value; } }
视图:
@using MyProject.Extensions { //... @Html.EnumDropDownListFor(model => model.CuriousQuestion) //... }
扩展(直接来自Simon Goldstone的答案 ,这里包括完整性):
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.ComponentModel; using System.Reflection; using System.Linq.Expressions; using System.Web.Mvc.Html; namespace MyProject.Extensions { //Extension methods must be defined in a static class public static class MvcExtensions { private static Type GetNonNullableModelType(ModelMetadata modelMetadata) { Type realModelType = modelMetadata.ModelType; Type underlyingType = Nullable.GetUnderlyingType(realModelType); if (underlyingType != null) { realModelType = underlyingType; } return realModelType; } private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } }; public static string GetEnumDescription<TEnum>(TEnum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); if ((attributes != null) && (attributes.Length > 0)) return attributes[0].Description; else return value.ToString(); } public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression) { return EnumDropDownListFor(htmlHelper, expression, null); } public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes) { ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); Type enumType = GetNonNullableModelType(metadata); IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>(); IEnumerable<SelectListItem> items = from value in values select new SelectListItem { Text = GetEnumDescription(value), Value = value.ToString(), Selected = value.Equals(metadata.Model) }; // If the enum is nullable, add an 'empty' item to the collection if (metadata.IsNullableValueType) items = SingleEmptyItem.Concat(items); return htmlHelper.DropDownListFor(expression, items, htmlAttributes); } } }
你想看看使用像Enum.GetValues
一个超级简单的方法来完成这件事 – 没有所有的扩展东西,似乎矫枉过正是这样的:
你的枚举:
public enum SelectedLevel { Level1, Level2, Level3, Level4 }
控制器内部将Enum绑定到列表:
List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();
之后,把它扔进ViewBag:
ViewBag.RequiredLevel = new SelectList(myLevels);
最后只需将其绑定到视图:
@Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class = "form-control" })
这是我发现的最简单的方法,不需要任何扩展或任何疯狂的东西。
更新 :见下面的安德鲁斯评论。
这是符文和奖的答案更改为使用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()) %>
请记住导入包含扩展方法的名称空间
<%@ 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
的项目是所选项目。
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
这是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)
如果你很高兴地添加Unconstrained Melody NuGet包(Jon Skeet的一个很好的小图书馆),我在这一个上很晚了,但是我发现了一个很酷的方法来完成这一行代码。
这个解决scheme更好,因为:
- 它确保(通用types约束)该值实际上是一个枚举值(由于无约束的旋律)
- 它避免了不必要的拳击(由于无约束的旋律)
- 它caching所有的描述,以避免在每次通话中使用reflection(由于无约束的旋律)
- 这是比其他解决scheme更less的代码!
所以,下面是这个工作的步骤:
- 在软件包pipe理器控制台中,“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() }); } }
现在,您已经在模型中公开了SelectListItem列表,您可以使用@ Html.DropDownList或@ Html.DropDownListFor使用此属性作为源。
基于Simon的回答,类似的方法是从Enum中获取Enum值,而不是Enum本身的描述属性。 如果您的站点需要使用多种语言进行渲染,并且如果要为Enums指定一个特定的资源文件,那么这很有帮助,您可以更进一步,并在Enum中添加Enum值,并通过扩展名引用它们例如[EnumName] _ [EnumValue]这样的约定 – 最终less打字!
然后,扩展名如下所示:
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()。 要做到这一点,我改变string模板看起来像这样
@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)) }
如果你感兴趣,我已经在我的博客上提供了更详细的答案:
现在,通过@Html.EnumDropDownListFor()
在MVC 5.1中支持此function。
检查以下链接:
http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum
根据上面的投票,微软用了5年的时间来实现如此需求的function真是令人遗憾!
此扩展方法的另一个修复 – 当前版本不select枚举的当前值。 我修正了最后一行:
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()); }
如果您想添加本地化支持,只需将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(资源)是你想要加载的资源,然后你得到本地化的string,也是有用的,如果你的枚举数具有多个字的值。
这是我的辅助方法的版本。 我使用这个:
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); }
You can also use my custom HtmlHelpers in Griffin.MvcContrib. 以下代码:
@Html2.CheckBoxesFor(model => model.InputType) <br /> @Html2.RadioButtonsFor(model => model.InputType) <br /> @Html2.DropdownFor(model => model.InputType) <br />
Generates:
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.
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() }); } }
@Simon Goldstone: Thanks for your solution, it can be perfectly applied in my case. The only problem is I had to translate it to 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))
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.
@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 ----"} } )
I found an answer here http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx ; however, some of my enums have [Description(...)]
attribute, so I've modified the code to provide support for that:
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 ); }
希望有所帮助。
@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- Create your ENUM
public enum LicenseType { xxx = 1, yyy = 2 }
2- Create your Service Class
public class LicenseTypeEnumService { public static Dictionary<int, string> GetAll() { var licenseTypes = new Dictionary<int, string>(); licenseTypes.Add((int)LicenseType.xxx, "xxx"); licenseTypes.Add((int)LicenseType.yyy, "yyy"); return licenseTypes; } public static string GetById(int id) { var q = (from p in this.GetAll() where p.Key == id select p).Single(); return q.Value; } }
3- Set the ViewBag in your controller
var licenseTypes = LicenseTypeEnumService.GetAll(); ViewBag.LicenseTypes = new SelectList(licenseTypes, "Key", "Value");
4- Bind your DropDownList
@Html.DropDownList("LicenseType", (SelectList)ViewBag.LicenseTypes)
Here a Martin Faartoft variation where you can put custom labels which is nice for localization.
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)