Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 18 de marzo de 2014
ASP.NET MVCSoportar 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 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)
EnumDropDownList in actionEl 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)")
EnumDropDownList with nullable types
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 del enum deben ceñirse a la sintaxis C# y esto puede limitar bastante en algunas ocasiones.

Dropdown list default textsPor 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.

Dropdown list with custom textsLa 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 atributo Display 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.

Localized resources
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”:

I18N in EnumDropDownListFor
Ejecución bajo cultura “en”:

image

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 clase EnumHelper.

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:

El chisty dijo...

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!

José María Aguilar dijo...

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!

El chisty dijo...

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

josé M. Aguilar dijo...

Hola!

Me alegro de que te sea de utilidad :)

Saludos