with mvc enumdropdownlistfor enum dropdownlist html asp.net-mvc data-binding drop-down-menu enums

html - with - enumdropdownlistfor mvc



¿Uniendo un Enum a un DropDownList en MVC 4? (7)

Esta pregunta ya tiene una respuesta aquí:

He estado encontrando por todas partes que la forma común de vincular Enums a DropDowns es a través de métodos de ayuda, que parece un poco dominante para una tarea aparentemente simple.

¿Cuál es la mejor manera de vincular Enums a DropDownLists en ASP.Net MVC 4?


Creo que se trata de la única forma (limpia), que es una pena, pero al menos hay algunas opciones por ahí. Recomiendo echar un vistazo a este blog: http://paulthecyclist.com/2013/05/24/enum-dropdown/

Lo sentimos, es demasiado largo para copiar aquí, pero lo esencial es que creó un nuevo método de ayuda HTML para esto.

Todo el código fuente está disponible en GitHub .


En mi controlador:

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

En mi vista:

@Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList)


Enums son compatibles con el marco desde MVC 5.1:

@Html.EnumDropDownListFor(m => m.Palette)

El texto mostrado puede ser personalizado:

public enum Palette { [Display(Name = "Black & White")] BlackAndWhite, Colour }

Enlace de MSDN: asp.net/mvc/overview/releases/mvc51-release-notes#Enum


Extender el ayudante html para hacerlo funciona bien, pero si desea poder cambiar el texto de los valores desplegables en función de las asignaciones de atributos de visualización, entonces deberá modificarlo de manera similar.

(Haga esto pre MVC 5.1, se incluye en 5.1+)

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


La solución de PaulTheCyclist es acertada. Pero no usaría RESX (¿Tendría que agregar un nuevo archivo .resx para cada nueva enumeración?)

Aquí está mi expresión HtmlHelper:

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

Así es como declaro mis enumeraciones:

[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, }

Y aquí está la llamada de un Razor View:

<div class="control-group span2"> <div class="controls"> @Html.EnumDropDownListFor(m => m.LoanType, new { @class = "span2" }) </div> </div>

Donde @Model.LoanType es una propiedad modelo del tipo LoanApplicationType

ACTUALIZACIÓN: Lo sentimos, se olvidó de incluir el código para la función de ayuda ToDescription ()

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


Técnicamente, no necesita un método auxiliar, ya que Html.DropdownListFor solo requiere un SelectList o Ienumerable<SelectListItem> . Simplemente puede convertir sus enumeraciones en una salida de este tipo y alimentarlo de esa manera.

Utilizo un método de biblioteca estática para convertir enumeraciones en List<SelectListItem> con algunos parámetros / opciones:

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

Su ViewModel puede pasar en las opciones que desee. Aquí hay una bastante compleja:

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

Por lo tanto, IEnumerable<SelectListItem> la DropDownList tu Vista contra esa IEnumerable<SelectListItem> .


Usted puede a esto:

@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))