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
Utilizzare Container Queries nominali
Escludere alcuni file da GitHub Secret Scanning
Gestione dei nomi con le regole @layer in CSS
Migliorare la scalabilità delle Azure Function con il Flex Consumption
Introduzione ai web component HTML
Eseguire script pre e post esecuzione di un workflow di GitHub
Gestire eccezioni nei plugin di Semantic Kernel in ASP.NET Core Web API
Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
Effettuare il refresh dei dati di una QuickGrid di Blazor
Ordine e importanza per @layer in CSS
Scrivere selettori CSS più semplici ed efficienti con :is()
Utilizzare DeepSeek R1 con Azure AI