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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
La gestione della riconnessione al server di Blazor in .NET 9
Gestire gli accessi con Token su Azure Container Registry
Recuperare App Service cancellati su Azure
Combinare Container Queries e Media Queries
Esporre i propri servizi applicativi con Semantic Kernel e ASP.NET Web API
Utilizzare Container Queries nominali
Selettore CSS :has() e i suoi casi d'uso avanzati
Escludere alcuni file da GitHub Secret Scanning
Migliorare la sicurezza dei prompt con Azure AI Studio
Rendere le variabili read-only in una pipeline di Azure DevOps
Ottimizzare le pull con Artifact Cache di Azure Container Registry
Autenticarsi in modo sicuro su Azure tramite GitHub Actions