简体   繁体   中英

Model Data passed from View to Controller is NULL

I have a view which is being populated correctly from a Model. Here is a cutdown of the View:

@model PickardOrdering.Models.ExhibitionItemModel

@foreach (var item in Model.Items)
    {
        <tr>
            <td>@Html.DisplayFor(modelItem => item.Code)</td>
            <td>@Html.DisplayFor(modelItem => item.Description)</td>
            <td>@Html.CheckBoxFor(modelItem => item.AdditionalItem.Value, new { @disabled = "disabled" })</td>
            <td>@Html.CheckBoxFor(modelItem => item.IsItemSelected.Value)</td>
            <td>£&nbsp;@Html.EditorFor(modelItem => item.ItemPrice)</td>
        </tr>
    }

<input type="submit" value="Save Items" />

When I post the data back to the controller, exhibitionitemmodel is null:

[HttpPost, ActionName("CreateExhibitionItems")]
    public ActionResult CreateExhibitionItems(ExhibitionItemModel exhibitionitemmodel)
    {
        decimal decPrice;
        if (ModelState.IsValid)
        {
            List<tblExhibitionItem> lstExhibitionItem = new List<tblExhibitionItem>();
            IEnumerable<ItemWrapper> lstItemWrapper = from objExhibitionItemModel in exhibitionitemmodel.Items
                                                                                                                select objExhibitionItemModel;

Here is the model class used:

namespace PickardOrdering.Models
{
    public class ItemWrapper : tblItem
    {
        public decimal ItemPrice { get; set; }
        public bool? IsItemSelected { get; set; }
    }

    public class ExhibitionItemModel
    {   
        public IEnumerable<ItemWrapper> Items { get; set; }
        public tblExhibition Exhibition { get; set; }
        public IEnumerable<tblExhibitionItem> ExhibitionItems { get; set; }
    }    
}

Any ideas why the model data is null?

Make sure you have a public parameterless constructor on every class you use in your model, including the enumerables and classes used by them.

Also, instantiate your included classes in the constructor. The model binder will need an instance of the objects to fill in. Example is below. Do this to all classes used by your model.

public class ExhibitionItemModel
{   

    public ExhibitionItemModel(){
        Exhibition = new tblExhibition();
        ExhibitionItems = new List<tblExhibitonItem>();
        Items = new List<ItemWrapper>();
    }

    public IEnumerable<ItemWrapper> Items { get; set; }
    public tblExhibition Exhibition { get; set; }
    public IEnumerable<tblExhibitionItem> ExhibitionItems { get; set; }
}    

Also, in your view, iterate your items using an index, not a foreach loop. This is so the view will generated with names containing indexes that the model binder can understand.

To make life easy on yourself with the model binding, I'd suggest making an EditorTemplate for your ItemWrapper class.

// Views/<WhateverYourControllerIsCalled>/EditorTemplates/ItemWrapper.cshtml

@model PickardOrdering.Models.ItemWrapper

<tr>
        <td>@Html.DisplayFor(m => m.Code)</td>
        <td>@Html.DisplayFor(m => m.Description)</td>
        <td>@Html.CheckBoxFor(m => m.AdditionalItem.Value, new { @disabled = "disabled" })</td>
        <td>@Html.CheckBoxFor(m => m.IsItemSelected.Value)</td>
        <td>&nbsp;@Html.EditorFor(m => m.ItemPrice)</td>
</tr>

And your main .cshtml becomes:

@model PickardOrdering.Models.ExhibitionItemModel

@using (Html.BeginForm("CreateExhibitionItems", "Home", FormMethod.Post))
{  
    <table>
    @Html.EditorFor(m => m.Items)
    </table>
    <input type="submit" value="Save Items" />
}

Using the EditorFor on your Items collection will render the html in the format that the default binder is expecting when binding to a list. You could render the html manually using an index and a for loop if you want finer control over it, but this way takes care of it for you.

And as a general tip that I find useful in these situations, add a FormCollection parameter to the action method that is receiving the post, and inspect this parameter during debugging. This helps to see what data is getting posted from the form, and from there you can figure out why it isn't being bound during model binding.

Is there any form in your CSHTML you can use this article You must use this code

@using (Html.BeginForm("CreateExhibitionItems", "controllerName", FormMethod.Post))
{  @foreach (var item in Model.Items)
    {
        <tr>
            <td>@Html.DisplayFor(modelItem => item.Code)</td>
            <td>@Html.DisplayFor(modelItem => item.Description)</td>
            <td>@Html.CheckBoxFor(modelItem => item.AdditionalItem.Value, new { @disabled = "disabled" })</td>
            <td>@Html.CheckBoxFor(modelItem => item.IsItemSelected.Value)</td>
            <td>£&nbsp;@Html.EditorFor(modelItem => item.ItemPrice)</td>
        </tr>
    }

<input type="submit" value="Save Items" />}

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