Possible bug in Html.DropDownList, selected values

2019-04-17 11:57发布

问题:

I know this has been asked a few times before, but the existing solutions look like hacks rather than a proper pattern.

I have a simple drop down list. I am trying to populate it with data and have a item pre selected. I am succeeding at the 'populate it with data part' but failing to get my preferred item pre-selected.

I am using ASP.NET MVC 3 RC2.

The important code bits:

{
    // Bunch of code
    CategoryOptions = new SelectList(categories, "Id", "Slug", article.Category.Id);
}

Now... the CategoryOptions is being passed to the Html helper like so:

@Html.DropDownListFor(a => a.Category, Model.CategoryOptions)

I have looked at the values being passed into the helper and have confirmed that one of the items has the selected value set to true:

However, it is not reflecting in the Html being generated by the helper. None of the ... tags have the selected="selected" attribute.

I used Reflector to examine the code a bit, and this line (SelectExtensions.SelectInternal) looks dicey:

item.Selected = (item.Value != null) ? set.Contains(item.Value) : set.Contains(item.Text);

Am I doing something wrong here? Or is the framework (ASP.NET MVC 3 RC2) at fault here.

回答1:

Ok... I just fixed it.

I changed around my view model to use a CategoryId instead of a Category slug. So now, my view looks like:

@Html.DropDownListFor(a => a.CategoryId, Model.CategoryOptions, new { @class = "ask-category-field" })

I think the model value being select (in this case, a => a.CategoryId) has to have the same type as the selected 'value.' (I will refine this explanation when I get more time to go over the framework code.) But clever coding indeed :) Hats of to ASP.NET MVC devs.

Now, it works perfectly as expect and also retains changes to the selected item across a PRG lifecycle.

Hope this helps someone.



回答2:

The selected property on a dropdown item doesn't actually set the dropdown item to be selected in the HTML.

I've experienced this problem myself before.

My solution to this was an extension method on the ViewDataDictionary that allows you to set the value of a given select list based on the selected item & a string Id of the select list.

public static void SetSelectedValueFor(this ViewDataDictionary viewDataDictionary, string key, IEnumerable<SelectListItem> items)
        {
            //  HACK: Store the selected item value in ViewData so that the DropDownListFor knows which one should be selected.
            //  It's a bit of a hack but it seems to be the only way I can do it since DropdownListFor ignores the Selected property on SelectListItem.
            var x = items.Where(c => c.Selected).FirstOrDefault();
            if (x != null)
            {
                viewDataDictionary[key] = x.Value;
            }
        }