Binding an Enum to a DropDownList in MVC 4?
我一直在各地发现,将枚举绑定到下拉列表的常见方法是通过helper方法,对于这样一个看似简单的任务,helper方法似乎有点霸道。
在ASP.NET MVC 4中将枚举绑定到DropDownList的最佳方法是什么?
你可以这样做:
1 | @Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e })) |
我认为这是唯一(干净)的方法,这是一个遗憾,但至少有几个选择。我建议你看看这个博客:http://paulthecyclist.com/2013/05/24/enum-dropdown/
抱歉,在这里复制太长,但要点是他为此创建了一个新的HTML助手方法。
所有源代码在GitHub上都可用。
自MVC 5.1以来,框架支持枚举:
1 | @Html.EnumDropDownListFor(m => m.Palette) |
可自定义显示的文本:
1 2 3 4 5 6 7 | public enum Palette { [Display(Name ="Black & White")] BlackAndWhite, Colour } |
msdn链接:http://www.asp.net/mvc/overview/releases/mvc51 release notes enum
在我的控制器中:
1 2 3 4 5 6 | var feedTypeList = new Dictionary<short, string>(); foreach (var item in Enum.GetValues(typeof(FeedType))) { feedTypeList.Add((short)item, Enum.GetName(typeof(FeedType), item)); } ViewBag.FeedTypeList = new SelectList(feedTypeList,"Key","Value", feed.FeedType); |
在我看来:
1 | @Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList) |
从技术上讲,您不需要辅助方法,因为
我使用静态库方法将枚举转换为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | public static List<SelectListItem> GetEnumsByType<T>(bool useFriendlyName = false, List<T> exclude = null, List<T> eachSelected = null, bool useIntValue = true) where T : struct, IConvertible { var enumList = from enumItem in EnumUtil.GetEnumValuesFor<T>() where (exclude == null || !exclude.Contains(enumItem)) select enumItem; var list = new List<SelectListItem>(); foreach (var item in enumList) { var selItem = new SelectListItem(); selItem.Text = (useFriendlyName) ? item.ToFriendlyString() : item.ToString(); selItem.Value = (useIntValue) ? item.To<int>().ToString() : item.ToString(); if (eachSelected != null && eachSelected.Contains(item)) selItem.Selected = true; list.Add(selItem); } return list; } public static class EnumUtil { public static IEnumerable<T> GetEnumValuesFor<T>() { return Enum.GetValues(typeof(T)).Cast<T>(); } // other stuff in here too... } /// <summary> /// Turns Camelcase or underscore separated phrases into properly spaces phrases ///"DogWithMustard".ToFriendlyString() =="Dog With Mustard" /// </summary> public static string ToFriendlyString(this object o) { var s = o.ToString(); s = s.Replace("__"," /").Replace("_",""); char[] origArray = s.ToCharArray(); List<char> newCharList = new List<char>(); for (int i = 0; i < origArray.Count(); i++) { if (origArray[i].ToString() == origArray[i].ToString().ToUpper()) { newCharList.Add(' '); } newCharList.Add(origArray[i]); } s = new string(newCharList.ToArray()).TrimStart(); return s; } |
您的视图模型可以传递您想要的选项。这是一个相当复杂的问题:
1 2 3 4 5 6 7 8 9 | public IEnumerable<SelectListItem> PaymentMethodChoices { get { var exclusions = new List<Membership.Payment.PaymentMethod> { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal }; var selected = new List<Membership.Payment.PaymentMethod> { this.SelectedPaymentMethod }; return GetEnumsByType<Membership.Payment.PaymentMethod>(useFriendlyName: true, exclude: exclusions, eachSelected: selected); } } |
因此,您将视图的
保尔骑手的解决方案就在眼前。但是我不会使用resx(我必须为每个新枚举添加一个新的.resx文件??)
下面是我的htmlhelper表达式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object attributes = null) { //Get metadata from enum var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var enumType = GetNonNullableModelType(metadata); var values = Enum.GetValues(enumType).Cast<TEnum>(); //Convert enumeration items into SelectListItems var items = from value in values select new SelectListItem { Text = value.ToDescription(), Value = value.ToString(), Selected = value.Equals(metadata.Model) }; //Check for nullable value types if (metadata.IsNullableValueType) { var emptyItem = new List<SelectListItem> { new SelectListItem {Text = string.Empty, Value = string.Empty} }; items = emptyItem.Concat(items); } //Return the regular DropDownlist helper return htmlHelper.DropDownListFor(expression, items, attributes); } |
以下是我如何声明我的枚举:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [Flags] public enum LoanApplicationType { [Description("Undefined")] Undefined = 0, [Description("Personal Loan")] PersonalLoan = 1, [Description("Mortgage Loan")] MortgageLoan = 2, [Description("Vehicle Loan")] VehicleLoan = 4, [Description("Small Business")] SmallBusiness = 8, } |
从剃刀的角度来看,这是一个要求:
1 | @Html.EnumDropDownListFor(m => m.LoanType, new { @class ="span2" }) |
其中,
更新:抱歉,忘记包含helper函数todescription()的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /// <summary> /// Returns Description Attribute information for an Enum value /// </summary> /// <param name="value"></param> /// <returns></returns> public static string ToDescription(this Enum value) { if (value == null) { return string.Empty; } var attributes = (DescriptionAttribute[]) value.GetType().GetField( Convert.ToString(value)).GetCustomAttributes(typeof (DescriptionAttribute), false); return attributes.Length > 0 ? attributes[0].Description : Convert.ToString(value); } |
扩展HTML助手以使其正常工作,但是如果您希望能够基于DisplayAttribute映射更改下拉值的文本,则需要对此进行类似的修改,
(执行MVC 5.1之前的操作,它包含在5.1+中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 = enumValues.Select(item => { var type = item.GetType(); var member = type.GetMember(item.ToString()); var attribute = member[0].GetCustomAttribute<DisplayAttribute>(); string text = attribute != null ? ((DisplayAttribute)attribute).Name : item.ToString(); string value = ((int)item).ToString(); bool selected = item.Equals(metadata.Model); return new SelectListItem { Text = text, Value = value, Selected = selected }; }); return html.DropDownListFor(expression, items, string.Empty, null); } |