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
Supportare il sorting di dati tabellari in Blazor con QuickGrid
Registrare servizi multipli tramite chiavi in ASP.NET Core 8
Eseguire un metodo asincrono dopo il set di una proprietà in Blazor 8
Eseguire le GitHub Actions offline
Implementare l'infinite scroll con QuickGrid in Blazor Server
Ottimizzare la latenza in Blazor 8 tramite InteractiveAuto render mode
Routing statico e PreRendering in una Blazor Web App
Ottimizzare il mapping di liste di tipi semplici con Entity Framework Core
Sfruttare al massimo i topic space di Event Grid MQTT
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Eseguire operazioni sui blob con Azure Storage Actions
Eseguire una GroupBy per entity in Entity Framework