简体   繁体   中英

Can't get (list of) object properties to bind from partial view

Hi I'm new to MVC and for my first project I'm getting stuck on binding post data to the view model. My colleagues who are more experienced in MVC have given up trying to solve it so now its up to the internet. I really believe this should not be hard, I'm messing up some convention or something. I know there's already a million questions on data binding out there but each one is subtlety different.

In my example it is the ColourSelectionDTO object that refuses to bind. When I get the postback to the controller the View Model has everything except ColourSelections. Actually, ColourSelections contains 5 instances of ColourSelectionDTO, but inside each of those instances, the properties are null.

That concludes my question (I need the ColourSelectionDTO's Properties to get binded), I'm now going to list cut down versions of the code, I've included namespaces in case I've missed a convention there, but not the using statements, please assume that side is correct, as the code does compile and run. Thanks guys.

ColourSelectionDTO.cs in namespace MyProject.Model.DTO

/// <summary>
/// intended as a view model for the partial view with the same name
/// </summary>
public class ColourSelectionDTO
{
    public string SelectedColourStr;
    public string Part;
}

SubmitOrderInputDTO.cs in namespace MyProject.Model.DTO.Ordering

public class SubmitOrderInputDTO
{
    public long JobNum { get; set; }

    public List<ColourSelectionDTO> ColourSelections { get; set; }

    //other properties that seem to bind fine
    ....

}

SubmitOrderVM.cs in MyProject.Web.ViewModels.JobNextActionSubmitOrder

public class SubmitOrderVM
{
    public SubmitOrderDTO Data { get; set; }
    public SubmitOrderInputDTO Inputs { get; set; }

}

SubmitOrder.cshtml in MyProject.Web.Views.JobNextActionSubmitOrder

@model SubmitOrderVM
@{
    ViewBag.Title = "Next Action - Submit Order";
    Layout = "~/Views/Job/_JobDetailsLayout.cshtml";
}

<div class="job-details-content">
@using (Html.BeginForm("SubmitOrder", "JobNextActionSubmitOrder", FormMethod.Post, new { id = "job-next-action-form" }))
{
    @Html.HiddenFor(m => m.Inputs.JobNum)
    @Html.ValidationSummary(false)

    <!--goes on for bunch of form stuff that I'm happy works ok-->

        for (int i = 0; i < Model.Data.AvailableColours.Keys.Count; i++)
        {
            //the index range for the loop does exactly match the index range of Model.Data.AvailableColours
            <div class="row">
                @Html.EditorFor(m => m.Inputs.ColourSelections[i])
            </div>
        }

    <!--more stuff that works including the submit button-->

ColourSelectionDTO.cshtml in MyProject.Web.Views.Shared.EditorTemplates

@Html.HiddenFor(m => m.Part) <!--value of part expected to be set by business layer-->
@Html.TextBoxFor(m => m.SelectedColourStr)

JobNextActionSubmitOrderController (simplified to show just the relevant bits)

public ActionResult Index(long jobNum)
{
    SubmitOrderVM submitVM = new SubmitOrderVM();
    submitVM.Data = _jobSubmitOrderBL.GetOrderForSubmission(jobNum);
    //below call will initialise the ColourSelections list and each ColourSelectionDTO
    //within, and sets the Part property but not the SelectedColourStr property
    submitVM.Inputs = _jobSubmitOrderBL.GetDefaultInputsForSubmitOrder(submitVM.Data);
    return View("SubmitOrder", submitVM);
}

    [HttpPost]
    public ActionResult SubmitOrder(SubmitOrderVM vm)
    {
        //this is where the vm.Inputs.ColourSelections[0..n] come back initalised
        //but .Part and .SelectedColourStr are null
        var result = _jobSubmitOrderBL.SubmitJobOrderAndProcessAllPossibleActions(vm.Inputs);
        return RedirectToAction("SubmitOrderResults");
    }

The html generated by the ColourSelectionDTO.cshtml is:

<input id="Inputs_ColourSelections_0__Part" name="Inputs.ColourSelections[0].Part" type="hidden" value="Walls" /> <!--value of part expected to be set by business layer-->
<input id="Inputs_ColourSelections_0__SelectedColourStr" name="Inputs.ColourSelections[0].SelectedColourStr" type="text" value="" />

And the post data looks like this

Inputs.JobNum:141085
Inputs.RequestedDeliveryDate:06/07/2014
Inputs.ColourSelections[0].Part:Walls
Inputs.ColourSelections[0].SelectedColourStr:testcol
Inputs.ColourSelections[1].Part:Roof
Inputs.ColourSelections[1].SelectedColourStr:blue
Inputs.ColourSelections[2].Part:Gutter
Inputs.ColourSelections[2].SelectedColourStr:orange
Inputs.ColourSelections[3].Part:CornerFlashing
Inputs.ColourSelections[3].SelectedColourStr:White
Inputs.ColourSelections[4].Part:RollerDoors
Inputs.ColourSelections[4].SelectedColourStr:Zinc
Inputs.IsAdditionalItemsChecked:true
Inputs.IsAdditionalItemsChecked:false
Inputs.IsBOMFinalised:false
Inputs.ClientOrderDocsSelected:DeliveryLetter
Inputs.ClientOrderDocsSendOptionsSelected:View
Inputs.IsSendGreensheet:false

MVC won't bind to variables in the Model, they need to be properties. In my case you can see the error in the first code snipet for ColourSelectionDTO. Was just a typo that I left off the { get; set; } part, but goes to show how a little mistake can leave you scratching your head a long time.

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