Popolare una lista con elementi di un Enum in ASP.NET MVC

di Marco De Sanctis, in ASP.NET MVC, Razor,

Quando la composizione di un certo insieme di elementi è nota a priori già in fase di compilazione (per esempio, i giorni della settimana), può essere preferibile rappresentare questo elenco con un enumerato, piuttosto che introdurre tabelle addizionali sulla base dati. Se questo approccio è molto comodo nella scrittura del codice, può invece presentare delle problematiche nel momento in cui vogliamo sfruttare i possibili valori per popolare una dropdown list. In questo caso, infatti, dobbiamo trasformare i membri dell'enumerato in un elenco di SelectListItem.

Il modo più comodo per farlo è quello di realizzare un'html helper, così che possiamo recuperarne la logica tutte le volte che ne abbiamo bisogno:

public static IHtmlString DropDownListFor<TModel, TEnum>(
  this HtmlHelper<TModel> html, 
  Expression<Func<TModel, TEnum>> expression) where TEnum : struct
{
  if (!typeof(TEnum).IsEnum)
    throw new ArgumentException("Il tipo deve essere un enum");

  // recuperiamo il valore corrente del model
  ModelMetadata model = ModelMetadata
    .FromLambdaExpression(expression, html.ViewData);
  var currentValue = model.Model;

  var items = Enum.GetValues(typeof(TEnum)).OfType<object>()
    .Select(x => new SelectListItem()
    {
      Value = x.ToString(),
      Text = GetDescription(x),
      Selected = currentValue != null && currentValue.Equals(x)
    });

    return html.DropDownListFor(expression, items);
}

Il metodo in alto ha la forma tipica degli html helper di ASP.NET MVC e accetta una expression che, dal model, permette di individuare una proprietà di tipo Enum; in realtà il vincolo è solo sulla sua natura di struct e, siccome non è possibile scrivere qualcosa di più restrittivo in c#, l'unica opzione è quella poi di effettuare una verifica a runtime.

Lo scopo del codice è sostanzialmente quello di eseguire una query LINQ che trasformi l'elenco dei possibili valori dell'enumerato in una lista di SelectListItem, che possono poi essere forniti all'helper DropDownListFor standard di ASP.NET MVC.
La clausola di Select, però, ha bisogno del valore corrente della proprietà del model, in modo da poter marcare il corrispondente elemento come Selected. Il modo più semplice per recuperare questo dato è sfruttare il ModelMetadata, come mostrato all'inizio del metodo, la cui proprietà Model contiene il dato che cerchiamo.

Un'ultima nota riguarda il valore che assegnamo alla proprietà Text: l'obiettivo è quello di poter marcare i vari elementi dell'enum con l'attributo DisplayAttribute in modo da supportare anche descrizioni personalizzate:

public enum SampleEnum
{
  [Display(Name = "Primo elemento")]
  First,
  [Display(Name = "Secondo elemento")]
  Second,
  [Display(Name = "Terzo elemento")]
  Third
}

Per questa ragione, l'helper originale sfrutta un metodo GetDescription che, tramite reflection, si occupa di verificare se questo attributo è presente nei vari valori dell'enumerato ed eventualmente lo sfrutta per recuperarne la descrizione:

private static string GetDescription(object value)
{
  if (value == null)
    return string.Empty;

  string result = value.ToString();
  var display = value.GetType()
    .GetMember(value.ToString()).First()
    .GetCustomAttributes(false)
    .OfType<DisplayAttribute>()
    .FirstOrDefault();

  if (display != null)
  {
    result = display.GetName();
  }

  return result;
}

L'utilizzo finale è davvero molto semplice:

@Html.DropDownListFor(x => x.EnumMyProperty);

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi