简体   繁体   中英

MVC4 model binding - Passing Custom View Models & values from view to controller

I have a strongly typed view with the following model.

public class ProductViewModel
{
    public Product Product { get; set; }
    public List<ProductOptionWithValues> ProductOptionsWithValues { get; set; }
}

public class ProductOptionWithValues
{
    public ProductOption ProductOption;
    public List<AllowedOptionValue> AllowedOptionValues;
}

I'm using this Model To populate a form where a user can select the options they want for a product. This is the view.

@model AsoRock.Entities.ViewModels.ProductViewModel

@{
    ViewBag.Title = "Details";
}
@using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) 
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    <h3> 
        @Html.DisplayFor(model => model.Product.ProductName)

        ----> @Html.DisplayFor(model => model.Product.Price) 
    </h3>
    <br/>

    foreach (var item in Model.ProductOptionsWithValues)
    {
        <b>@Html.DisplayFor(modelItem => item.ProductOption.Option.OptionName)</b>
        <br/>

        @Html.DropDownListFor(m => m.ProductOptionsWithValues, 
                new SelectList(item.AllowedOptionValues, 
                "Id", "DisplayString", 
                item.AllowedOptionValues.First().Id))
        <br/>
    }
    <input type="submit" value="Add to cart" />
}

In my controller I am trying to pass the model back. When I set a break point in the controller it hits it but the Product view model is empty, any ideas how I can get the values that are selected in the view back in to my controller?

[HttpPost]
public ActionResult Details(ProductViewModel ProductViewModel)
{
    return View();
    //return View();
}

As mentioned in the comments, you need to change the name of the viewmodel parameter from ProductViewModel to something else eg

[HttpPost]
public ActionResult Details(ProductViewModel viewModel)
{
}

Now it's very odd that the viewModel param is not set to an instance of the class. The MVC model binder will still create an instance of ProductViewModel even if none of it's properties are set to anything. You're not using a custom model binder by any chance?

Also I would very strongly suggest that your viewmodel class does not have a Product property. Instead, create properties in the viewmodel specifically for the Product properties you intend to use eg

public class ProductViewModel
{
    public string ProductName { get; set; }
    public decimal ProductPrice { get; set; }
    public List<ProductOptionWithValues> ProductOptionsWithValues { get; set; }
}

Using Product in the viewmodel sort of defeats the point of having a viewmodel. The viewmodel should contain only the bare minimum that the view needs. Including Product means the viewmodel is now bloated with extra data it does not use/need.

EDIT:

In your shoes, I would strip down the view itself, using only little bits of the viewmodel, and POST to the controller to see what happens. If the viewmodel calss is not NULL, go back to the view and add another bit back. Keep doing this until the viewmodel is NULL again. Doing this bit by bit should help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM