-->

MVC4 binding drop down list in a list (bug)

2019-04-10 19:36发布

问题:

I have the below code in a view. (index.cshtml)

Binding Problem

  • The first drop down selects the correct value, based on the 'ChildItem' editor template.
  • The second example using an inline drop down list does not work I don't want to create an editor template just to display drop down values.
  • The odd thing is that TextBoxFor will show the correct value. This seems to be an issue just with the drop down list.

How do I fix the binding so that the second drop down works? I debugged it. It would appear that ViewData.Eval is not picking up the correct value from _.Children[i].ChooseId.

Update (bug)
This is a confirmed bug (low priority, how?) in the MVC framework http://aspnet.codeplex.com/workitem/8311

@using (Html.BeginForm())
{
    for (int i = 0; i < Model.Children.Count(); i++)
    {
       <p>A: @Html.EditorFor(_ => _.Children[i], "ChildItem")</p>
       <p>B: @Html.DropDownListFor(_ => _.Children[i].ChooseId, TestModel.PeopleSelect)</p>
    }
    <button type="submit">GO</button>
}

I have tried using DropDownListFor(_ => Model.Children[i].ChooseId), same result.
using TextBoxFor(_ => _.Children[i].ChooseId) shows the correct value, wierd?

For reference here is ChildItem.cshtml

@using dropdown.Controllers
@using dropdown.Models
@model dropdown.Models.TestPerson
@Html.DropDownListFor(_ => _.ChooseId, TestModel.PeopleSelect)

It looks like this:

回答1:

I have subsequently found this: http://aspnet.codeplex.com/workitem/8311 It's a confirmed bug.

The only workaround i have found is this.

Mark Selected Item

@Html.DropDownListFor(_ => _.Children[i].ChooseId, Mark(TestModel.PeopleSelect, Model.Children[i].ChooseId))

Mark Function / Extension Method

@functions {
    private IEnumerable<SelectListItem> Mark(IEnumerable<SelectListItem> items, object Id)
    {
        foreach (var item in items)
            if (string.CompareOrdinal(item.Value, Convert.ToString(Id)) == 0)
                item.Selected = true;
        return items;
    }
}


回答2:

You could put the items into a partial view and load that for your child objects, OR...

You could opt to do a foreach loop on the child collection, and use it like this:

foreach (var itm in Model.Children)
{
    @Html.DropDownListFor(modelItem => itm.ChooseId,
          new SelectList( (IEnumerable<SelectListItem>)TestModel.PeopleSelect, "Value", "Text", itm.ChooseId),
          htmlAttributes: new { @class = "form-control" }
    )
}

This assumes that TestModel.PeopleSelect has been created as a SelectListItem[] or IEnumerable<SelectListItem>. Code to do that properly is in my answer on a related question: ASP.NET MVC4 Model's Child Collection Drop Down List not binding properly

Doing a for loop on the child collection gave me the error:

Cannot apply indexing with [] to an expression of type 'ICollection<Children>'

So I wouldn't recommend that.