-->

Model binding for a ViewModel containing multiple

2019-08-16 22:37发布

问题:

I have a strongly typed view of type ProductListingViewModel which in turn contains a ProductViewModel. (both custom view models).

I have some form elements on my page and these are created like so:

<%: Html.DropDownListFor(m => m.ProductViewModel.CategoryId, Model.Categories)%>

which generates the HTML:

<select name="ProductViewModel.CategoryId" id="CategoryId">

With the default model binding I expected that when I post to my controller action which accepts a parameter of type ProductListingViewModel, that it'd know to populate the ProductViewModel.CategoryId with the relevant data.

The name of the select list seems to indicate that it knows there's a ProductViewModel with a CategoryId property however when I post to my controller method, the ProductViewModel is null. If I create this during construction of the ProductListingViewModel then it's no longer null but the default binder doesn't seem to be populating the properties as I expected.

Is this a case for a custom model binder or am I just missing something fundamental?

Cheers.

回答1:

Let me try to summarize (correct me if I am wrong).

Model:

public class ProductListingViewModel
{
    public ProductViewModel ProductViewModel { get; set; }
    public IEnumerable<SelectListItem> Categories { get; set; }
}

public class ProductViewModel
{
    public string CategoryId { get; set; }
}

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new ProductListingViewModel
        {
            Categories = new SelectList(new[]
            {
                new { Value = "1", Text = "category 1" },
                new { Value = "2", Text = "category 2" }
            }, "Value", "Text")
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(ProductListingViewModel model)
    {
        return View(model);
    }
}

View:

<% using (Html.BeginForm()) { %>
    <%: Html.DropDownListFor(m => m.ProductViewModel.CategoryId, Model.Categories)%>
    <input type="submit" value="OK" />
<% } %>

Now when you submit the form you will get:

model.ProductViewModel.CategoryId = the id that was selected in the drop down list

Isn't what you are after?



回答2:

It seems to me that the default binder should work in this case.

Did you try using Fiddler for checking the data sent from the client?

What exactly is the signature of the controller action?