Click here to Skip to main content
15,885,365 members
Articles / Web Development / XHTML

Automatic Dropdown Lists for Razor Views

Rate me:
Please Sign up or sign in to vote.
4.31/5 (11 votes)
21 Jan 2018CPOL2 min read 44.5K   25   13
Using a metadata attribute and editor template for DropDown lists in Razor

Introduction

This article shows how we can apply a DropDownList metadata attribute to a View Model property, and have a DropdDownList rendered by the EditorFor HTML helper.

Background

I'm a big fan of runtime scaffolding in ASP.NET MVC. This is where you use e.g. the EditorFor HTML Helper to decide how to render an HTML element for a property of your view model. For example, if a property is marked with the DataType attribute and that indicates the property's DataType is DateTime, then it will automatically render a date picker. For integer properties, EditorFor renders an UpDown spinner control. If EditorFor works smoothly for all your properties, you can use a single EditorForModel element to render your whole view model into the view correctly.

Using the Code

Using this system involves new code and changed code in several areas of your MVC application. It is not just a library or plug in, although I have plans for version 2 to use Unity at these points where I modify the code.

C#
public class DemoModel
{
    [DropDownList("LanguageSelect")]
    public int? LanguageId { get; set; }
    public SelectList LanguageSelect { get; set; } 
} 

Now when I use the Razor markup @EditorFor(m => m.LanguageId), I get a drop-down populated from the LanguageSelect list. I get this because the DropDownListAttrbute class attaches the select list name to the LanguageId model:

C#
public class DropDownListAttribute : UIHintAttribute, IMetadataAware
{
    public DropDownListAttribute(string selectListName) : 
              base(KnownUiHints.DropDown, KnownPresentationLayers.Mvc, selectListName)
    {
        SelectListName = selectListName;
    }
    public string SelectListName { get; set; }
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        var listProp = metadata.ContainerType.GetProperty(SelectListName);
        metadata.AdditionalValues[KnowMetadataKeys.SelectListName] = SelectListName;
    }
} 

All my view models derive from ViewModel, which offers a SelectListDictionary property:

C#
private IDictionary<string,> _selectListdictionary;
public virtual IDictionary<string,> SelectListDictionary
{
    get
    {
        if (_selectListdictionary == null)
        {
            var props = GetType().GetProperties().Where(p => p.PropertyType == typeof(SelectList));
            _selectListdictionary = props.ToDictionary
                    (prop => prop.Name, prop => (SelectList)prop.GetValue(this, null));
        }
        return _selectListdictionary;
    }
}

In my base controller, I override the View method to pull the entire select list dictionary from the view model, and insert it into the view's viewdata, making it available for the editor template:

C#
protected override ViewResult View(string viewName, string masterName, object model)
{
    var result = base.View(viewName, masterName, model);
    if ((model is ViewModel) && (!ViewData.ContainsKey(KnowMetadataKeys.ViewDataSelectLists)))
    {
        var vm = (ViewModel)model;
        result.ViewData.Add(KnowMetadataKeys.ViewDataSelectLists, vm.SelectListDictionary);
    }
    return result;
}

Said editor template:

C#
@using Erisia.Constants
@{
    var list = (SelectList)ViewData.ModelMetadata.AdditionalValues
        [ViewData.ModelMetadata.AdditionalValues[KnowMetadataKeys.SelectListName].ToString()];
    var listWithSelected = new SelectList(list.Items, list.DataValueField, list.DataTextField, Model);
}
@Html.DropDownListFor(m => Model, listWithSelected, " - select - ")

Remarks

There are probably some better ways of doing this, and populating the select list inside the view model is probably not too kosher, but this little 'framework' has saved me so much time on so many projects, and I've just received a glowing compliment for it on Code Review beta. It's been way too long since I wrote an article and I thought sharing this would make a good one.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Erisia Web Development
South Africa South Africa
I am a software developer in Johannesburg, South Africa. I specialise in C# and ASP.NET MVC, with SQL Server, with special fondness for MVC and jQuery. I have been in this business for about eighteen years, and am currently trying to master Angular 4 and .NET Core, and somehow find a way to strengthen my creative faculties.
- Follow me on Twitter at @bradykelly

Comments and Discussions

 
SuggestionAdding Code For Constants Pin
Member 94777712-Apr-14 3:30
Member 94777712-Apr-14 3:30 
GeneralRe: Adding Code For Constants Pin
Brady Kelly2-Apr-14 3:46
Brady Kelly2-Apr-14 3:46 
GeneralRe: Adding Code For Constants Pin
Member 94777712-Apr-14 8:06
Member 94777712-Apr-14 8:06 
QuestionAutomatic Dropdpown Lists for Razor Views Pin
rajacsharp530-Dec-13 5:09
rajacsharp530-Dec-13 5:09 
Questiondemo? Pin
Mehmet TEMEL29-Dec-13 10:17
Mehmet TEMEL29-Dec-13 10:17 
where is demo?
AnswerRe: demo? Pin
Brady Kelly29-Dec-13 14:55
Brady Kelly29-Dec-13 14:55 
GeneralRe: demo? Pin
thatraja29-Dec-13 23:04
professionalthatraja29-Dec-13 23:04 
GeneralRe: demo? Pin
Brady Kelly29-Dec-13 23:50
Brady Kelly29-Dec-13 23:50 
SuggestionRe: demo? Pin
Keith Barrow30-Dec-13 0:04
professionalKeith Barrow30-Dec-13 0:04 
GeneralRe: demo? Pin
BillWoodruff30-Dec-13 1:41
professionalBillWoodruff30-Dec-13 1:41 
GeneralRe: demo? Pin
Keith Barrow30-Dec-13 2:01
professionalKeith Barrow30-Dec-13 2:01 
GeneralRe: demo? Pin
BillWoodruff30-Dec-13 2:28
professionalBillWoodruff30-Dec-13 2:28 
SuggestionRe: demo? Pin
thatraja30-Dec-13 1:12
professionalthatraja30-Dec-13 1:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.