martes, 18 de marzo de 2014
Soportar de forma medio decente tipos enumerados (enums) no era algo que no pudiéramos hacer con versiones anteriores de ASP.NET MVC, pero ya iba siendo hora de que el producto incluyera de serie herramientas para facilitarlo un poco. Y por fin, la revisión 5.1 de ASP.NET MVC algo ha aportado al respecto :)
En primer lugar, MVC 5.1 ha añadido a la colección de helpers HTML el extensor
Como se puede observar, la ejecución del helper ha generado un desplegable en el que es posible seleccionar exclusivamente los valores disponibles en el enumerado.
Si en cambio la propiedad a editar fuera anulable (Nullable<Color> o Color? en C#), el framework añadirá automáticamente un primer elemento en blanco, cuya selección asignaría el valor nulo a la propiedad. Por supuesto, es posible modificar la forma de presentar este elemento nulo utilizando sobrecargas del helper:
El resultado en este caso sería el mostrado también a la derecha.
Y antes de seguir, un par de curiosidades. Primero, no existe un equivalente no tipado al helper, es decir, por alguna razón no se ha seguido el mismo criterio que en otros casos, donde por ejemplo teníamos un helper
Tampoco se han modificado las plantillas de edición por defecto de MVC 5. Por tanto, siguiendo con el ejemplo anterior, una llamada a
Por ejemplo, considerad el siguiente caso, cuyo resultado en ejecución vemos a la derecha:
La forma de solucionar esto sería bien sencilla. Basta con utilizar el conocido atributo
El primero de ellos,
En el siguiente ejemplo, obtenemos la lista con el valor
Para evitar errores y poder comprobar de antemano si los valores que vamos a suministrar a
Publicado en Variable not found.
En primer lugar, MVC 5.1 ha añadido a la colección de helpers HTML el extensor
EnumDropDownListFor()
, que, como su nombre indica, crea un cuadro desplegable para seleccionar valores de un tipo enumerado (o un nullable de dicho tipo):// Model: public enum Color { Black, White, Green, Blue, Red } public class Point { public int X { get; set; } public int Y { get; set; } public Color Color { get; set; } } // View: @model Point ... @Html.LabelFor(m => m.Color) @Html.EnumDropDownListFor(m => m.Color)El resultado en tiempo de ejecución sería el mostrado a la derecha.
Como se puede observar, la ejecución del helper ha generado un desplegable en el que es posible seleccionar exclusivamente los valores disponibles en el enumerado.
Si en cambio la propiedad a editar fuera anulable (Nullable<Color> o Color? en C#), el framework añadirá automáticamente un primer elemento en blanco, cuya selección asignaría el valor nulo a la propiedad. Por supuesto, es posible modificar la forma de presentar este elemento nulo utilizando sobrecargas del helper:
@Html.EnumDropDownListFor(m => m.Color, "(None)")
El resultado en este caso sería el mostrado también a la derecha.
Y antes de seguir, un par de curiosidades. Primero, no existe un equivalente no tipado al helper, es decir, por alguna razón no se ha seguido el mismo criterio que en otros casos, donde por ejemplo teníamos un helper
Html.TextBox()
y otro Html.TextBoxFor()
. Aquí sólo podremos usar la versión tipada.Tampoco se han modificado las plantillas de edición por defecto de MVC 5. Por tanto, siguiendo con el ejemplo anterior, una llamada a
Html.EditorFor(m=>m.Color)
no mostrará un desplegable, sino la caja de texto básica, pero ya vimos por aquí hace hace tiempo cómo solucionarlo.¿Y podemos cambiar los nombres de los elementos que aparecen en el desplegable?
Pues sí. De hecho, hay muchos casos en los que será conveniente modificar el texto que aparece en el desplegable, puesto que los nombres de los elementos delenum
deben ceñirse a la sintaxis C# y esto puede limitar bastante en algunas ocasiones.Por ejemplo, considerad el siguiente caso, cuyo resultado en ejecución vemos a la derecha:
// Model public enum Language { CSharp, VbNet, FSharp, NodeJs } // View: @model Generator ... @Html.EnumDropDownListFor(m => m.Language)Está claro que el contenido del desplegable no es lo que un usuario de nuestra aplicación esperaría ver, puesto que estamos condicionando el UI por las limitaciones de sintaxis del lenguaje en el que hemos implementado el tipo
Language
.La forma de solucionar esto sería bien sencilla. Basta con utilizar el conocido atributo
[Display]
en cada elemento del enumerado para proporcionar una descripción alternativa al mismo:public enum Language { [Display(Name = "C#")] CSharp, [Display(Name = "VB.NET")] VbNet, [Display(Name = "F#")] FSharp, [Display(Name = "NodeJS")] NodeJs }
¿Y ocurre si mi aplicación es multi-idioma?
Pues sin problema, podemos utilizar también el atributoDisplay
como hacemos habitualmente en este tipo de escenarios. Simplemente usaremos su parámetro ResourceType
para indicar la clase a través de la cual podemos acceder al texto localizado, y Name
para la clave del mismo.public enum Color { [Display(Name="Black", ResourceType=typeof(ColorResources))] Black, [Display(Name="White", ResourceType = typeof(ColorResources))] White, [Display(Name="Green", ResourceType = typeof(ColorResources))] Green, [Display(Name = "Blue", ResourceType = typeof(ColorResources))] Blue, [Display(Name = "Red", ResourceType = typeof(ColorResources))] Red }De esta forma, el texto mostrado dependerá de la cultura del hilo de ejecución:
Ejecución bajo cultura “es”: | Ejecución bajo cultura “en”: |
Helpers adicionales
Para cubrir aquellos casos en los que se desee tener más control sobre la generación del HTML, ASP.NET MVC 5.1 proporciona un par de helpers adicionales que pueden ser de utilidad a través de la claseEnumHelper
.El primero de ellos,
EnumHelper.GetSelectList()
, retorna una lista de objetos SelectListItem
partiendo de un tipo enumerado, lista para ser utilizada en los tradicionales helpers como Html.DropDroList()
o bien para recorrerla y generar manualmente el HTML del control de selección. En todos los casos, la lista retornada tendrá en cuenta las descripciones (localizadas o no) introducidas mediante el atributo Display
en los elementos, y asegurará que los valores asignados a cada elemento en el desplegable son correctos.En el siguiente ejemplo, obtenemos la lista con el valor
Color.Red
seleccionado por defecto, y mostramos por pantalla el desplegable usando el helper clásico:@{ var list = EnumHelper.GetSelectList(typeof(Color), Color.Red); } ... @Html.DropDownListFor(m=>m.Color, list)Otra sobrecarga facilita su uso en plantillas de edición, pues permite generar directamente la lista partiendo de los metadatos del modelo que recibe la vista, permitiendo así soluciones más genéricas que no dependan del tipo concreto de enumerado.
Para evitar errores y poder comprobar de antemano si los valores que vamos a suministrar a
GetSelectList()
son correctos, podemos utilizar el helper EnumHelper.IsValidForEnumHelper()
, que básicamente retornará true
si se trata de un enum
, pero siempre que no sean flags, pues no se permite la selección múltiple.Publicado en Variable not found.
4 Comentarios:
Excelente guia que estoy usando en mi proyecto MVC para hacer mas sencillo un par de formularios. Una pregunta sencilla. ¿Puedo sobreescribir de alguna manera alguno de los elementos html que me genera el Helper tipado, como por ejemplo el "name" del input? Gracias y un saludo!
Hola!
En ese caso lo más sencillo es que uses las versiones no tipadas de los helpers (ej: Html.DropwdownList), en las que sí puedes suministrar ese dato. Pero puedes usar los helpers adicionales descritos en la última sección del post (como EnumHelper.GetSelectList) para obtener los valores a mostrar en el desplegable.
Gracias por comentar y un saludo!
Efectivamente así lo he hecho y ha ido genial. Sigo desde hace poco su blog y creo que es ESENCIAL para alguien que se adentra en ASPNET MVC. No se queda en la superficie y da un monton de ideas/ayudas para desrrollar proyectos en esta tecnología. Estoy muy contento de haberla reencontrado después de mucho tiempo.
Un saludo
Hola!
Me alegro de que te sea de utilidad :)
Saludos
Enviar un nuevo comentario