[SOLVED] How does the following code work in mvc3?

Issue

My controller code

public ActionResult Create(string id)
    {
        ViewBag.ALLO_ID = new SelectList(_unitOfWork.AllocationMRepository.Get(), "ALLO_ID", "ALLO_ID", id);
        ViewBag.TERR_ID = new SelectList(_unitOfWork.TerrListRepository.Get().OrderBy(m => m.TERR_ID), "TERR_ID", "TERR_ID");
        ViewBag.ITEM_ID = new SelectList(_unitOfWork.SampleInfo.Get(), "ITEM_ID", "ITEM_ID");
        return View();
    } 

In my view

<div class="editor-field">
                @Html.DropDownList("ALLO_ID", String.Empty)
                @Html.ValidationMessageFor(model => model.ALLO_ID)
            </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.TERR_ID, "Territory Name")
        </div>
        <div class="editor-field">
            @Html.DropDownList("TERR_ID", String.Empty)
            @Html.ValidationMessageFor(model => model.TERR_ID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ITEM_ID, "Item Name")
        </div>
        <div class="editor-field">
            @Html.DropDownList("ITEM_ID", String.Empty)
            @Html.ValidationMessageFor(model => model.ITEM_ID)
        </div>

How these drop drop lists are created? It is not very much clear to me. I want to know how does it work.

Solution

Grab the source and build it on your machine. Seriously. I refer to my copy frequently.

To answer your specific question, i.e. “how is the framework creating dropdown lists?” It’s iterating through an enumerable collection and creating a string.

The MVC libraries define numerous extension methods for the HtmlHelper class. You can easily define your own. Of course, you can build other helper classes, but HtmlHelper is readily available for just this purpose.

Stepping through a few layers of overloads, we find:

private IHtmlString BuildDropDownList(string name, string defaultOption, IEnumerable<SelectListItem> selectList, 
            object selectedValue, IDictionary<string, object> htmlAttributes) {

    var modelState = ModelState[name];
    if (modelState != null) {
        selectedValue = selectedValue ?? ModelState[name].Value;
    }
    selectedValue = ConvertTo(selectedValue, typeof(string));

    if (selectedValue != null) {
        var newSelectList = new List<SelectListItem>(from item in selectList select new SelectListItem(item));
        var comparer = StringComparer.InvariantCultureIgnoreCase;
        var selectedItem = newSelectList.FirstOrDefault(item => item.Selected || comparer.Equals(item.Value ?? item.Text, selectedValue));
        if (selectedItem != default(SelectListItem)) {
            selectedItem.Selected = true;
            selectList = newSelectList;
        }
    }

    TagBuilder tagBuilder = new TagBuilder("select") {
        InnerHtml = BuildListOptions(selectList, defaultOption)
    };
    tagBuilder.MergeAttributes(htmlAttributes);
    tagBuilder.MergeAttribute("name", name, replaceExisting: true);
    tagBuilder.GenerateId(name);

    // If there are any errors for a named field, we add the css attribute.
    AddErrorClass(tagBuilder, name);

    return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}

It’s really not that complicated. The extension methods which use the “For” suffix are a bit more sophisticated.

@Html.LabelFor(model => model.TERR_ID, "Territory Name")

Notice the lambda expression? The framework doesn’t actually execute it; instead, it parses it as metadata and uses it to get the fully-qualified name of the item. This can then be used to retrieve various information from the original property, such as DataAnnotations pertaining to validation.

The crux of the implementation is in private static MvcHtmlString SelectInternal(...), contained in System.Web.Mvc.Html.SelectExtensions. The integration with model state and validation is noteworthy.

Answered By – Tim M.

Answer Checked By – Gilberto Lyons (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *