简体   繁体   中英

ASP.NET MVC3: View POSTed model value is NULL

I have the following controller and view. It is listing the values correctly using GET. When I click on the button it causes a POST. However the value received in the controller is NULL. How do we correct it?

HIGHLIGHTED CODE

    [HttpPost]
    public ActionResult CastVote(IEnumerable<Program> theProgramList)

GET Image

在此处输入图片说明

CODE

 public enum RatingEnum { Poor = 0, Neutral, Good, Excellent };

public class Program
{
    public int ProgramID { get; set; }
    public string ProgramName { get; set; }
    public RatingEnum RatingID { get; set; }
    public string ProgramCategory { get; set; }
}

CONTROLLER

namespace MyProgramRatingApp.Controllers
{
public class ProgramController : Controller
{




    List<Program> programList = new List<Program>()
                          {
                            new Program
                            {
                                ProgramID = 1,ProgramName = "Program1",
                                ProgramCategory = "A"
                            },
                            new Program
                            {
                                ProgramID = 2,ProgramName = "Program2",
                                ProgramCategory = "B"
                            },
                            new Program
                            {
                                ProgramID = 3,ProgramName = "Program3",
                                ProgramCategory = "A"
                            }

                          };




    // GET: /Program/
    public ActionResult CastVote()
    {
        ViewBag.RatingEnum = GetRstingSelectList();
        return View(programList);
    }


    // POST: /StoreManager/Create
    [HttpPost]
    public ActionResult CastVote(IEnumerable<Program> theProgramList)
    {
        if (ModelState.IsValid)
        {
            //Save the book in DB first and then redirectToAction.


            return RedirectToAction("CastVote");
        }

        return View(theProgramList);
    }


    public static SelectList GetRstingSelectList()
    {
        Array values = Enum.GetValues(typeof(RatingEnum));
        List<System.Web.UI.WebControls.ListItem> items = new List<System.Web.UI.WebControls.ListItem>(values.Length);

        foreach (var i in values)
        {
            items.Add(new System.Web.UI.WebControls.ListItem
                                    {
                                        Text = Enum.GetName(typeof(RatingEnum), i),
                                        Value = ((int)i).ToString()
                                    }
                       );
        }

        return new SelectList(items);
    }


    }
}

VIEW

@model IEnumerable<MyProgramRatingApp.Program>

@{
ViewBag.Title = "CastVote";
}

<h2>CastVote</h2>

@using (Html.BeginForm())
{
<table>
    <tr>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramName
        </th>
        <th style="border:1px solid Teal; background-color:Gray">
            RatingID
        </th>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramCategory
        </th>
        <th style="border:1px solid Teal; background-color:Gray"></th>
    </tr>

@foreach (var item in Model)
{
    <tr>
        <td style="border:1px solid Teal">
            @Html.DisplayFor(modelItem => item.ProgramName)
        </td>
        <td style="border:1px solid Teal">
            @Html.DisplayFor(modelItem => item.RatingID)
        </td>
        <td style="border:1px solid Teal">
            @Html.DisplayFor(modelItem => item.ProgramCategory)
        </td>
        <td style="border:1px solid Teal">
            @Html.DropDownListFor(model => item.RatingID, (SelectList)ViewBag.RatingEnum, String.Empty)
        </td>

    </tr>
}

</table>

<p>
    <input type="submit" value="Cast Vote" />
</p>

}

READING:

  1. dropdownlist set selected value in MVC3 Razor

  2. ASP.NET MVC 3 - Partial vs Display Template vs Editor Template

  3. IEnumerable property with MVC3 EditorTemplate

  4. ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

  5. Model Binding To A List


Replace the foreach loop in your view with a call to an editor template:

@model IEnumerable<MyProgramRatingApp.Program>

@{
    ViewBag.Title = "CastVote";
}

<h2>CastVote</h2>

@using (Html.BeginForm())
{
    <table>
        <tr>
            <th style="border:1px solid Teal; background-color:Gray">
                ProgramName
            </th>
            <th style="border:1px solid Teal; background-color:Gray">
                RatingID
            </th>
            <th style="border:1px solid Teal; background-color:Gray">
                ProgramCategory
            </th>
            <th style="border:1px solid Teal; background-color:Gray"></th>
        </tr>

        @Html.EditorForModel()

    </table>

    <p>
        <input type="submit" value="Cast Vote" />
    </p>
}

and then define the editor template which will be automatically rendered for each element in the model ( ~/Views/Shared/EditorTemplates/Program.cshtml ):

@model MyProgramRatingApp.Program
<tr>
    <td style="border:1px solid Teal">
        @Html.EditorFor(x => x.ProgramName)
    </td>
    <td style="border:1px solid Teal">
        @Html.EditorFor(x => x.RatingID)
    </td>
    <td style="border:1px solid Teal">
        @Html.EditorFor(x => x.ProgramCategory)
    </td>
    <td style="border:1px solid Teal">
        @Html.DropDownListFor(
             x => x.RatingID, 
             (SelectList)ViewBag.RatingEnum, 
             String.Empty
        )
    </td>
</tr>

Notice that I have used @Html.EditorFor in the editor template instead of @Html.DisplayFor in order to generate input fields. If you don't do that you won't get any values back in the controller because your form doesn't contain any input elements. If you don't want to show input fields you could use hidden inputs:

@model MyProgramRatingApp.Program
<tr>
    <td style="border:1px solid Teal">
        @Html.DisplayFor(x => x.ProgramName)
        @Html.HiddenFor(x => x.ProgramName)
    </td>
    <td style="border:1px solid Teal">
        @Html.DisplayFor(x => x.RatingID)
        @Html.HiddenFor(x => x.RatingID)
    </td>
    <td style="border:1px solid Teal">
        @Html.DisplayFor(x => x.ProgramCategory)
        @Html.HiddenFor(x => x.ProgramCategory)
    </td>
    <td style="border:1px solid Teal">
        @Html.DropDownListFor(
             x => x.RatingID, 
             (SelectList)ViewBag.RatingEnum, 
             String.Empty
        )
    </td>
</tr>

The editor template will generate correct names for the input fields so that the model binder correctly binds the values.

You may also take a look at the following article to better understand the wire format that is expected for collections.

this code work for me:

  1. Controller: [HttpPost] public ActionResult CastVote(Ilist theProgramList)

2 View:

@model IList<Program>
@using (Html.BeginForm())
{
<table>
    <tr>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramName
        </th>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramCategory
        </th>
        <th style="border:1px solid Teal; background-color:Gray">  </th>
    </tr>

@for(var i=0,j=mode.Count;i<j;i++)
{
  <tr>
     <td>@model[i].ProgrameName</td>
     <td><input type="text" name="RaingID[@i]" value="@model[i].RatingID"</td>


      <td>
        @Html.DropDownListFor(x => x.Rating, 
                      (SelectList)ViewBag.RatingEnum, new {@name="ProgramCategory[i] "})
     </td>
  </tr>
}
<p>
    <input type="submit" value="Cast Vote" />
</p>

</table>

}

Thanks to Darin. I have accepted his answer. The complete solution is posted for the benefit of others reading this.

Note: EditorTemplate helped to avoid foreach loop and helped in proper object binding.

Note: The EditorTemplate should be placed in proper folder and the filename should be based on convention.

//Model

namespace MyProgramRatingApp
{
public enum RatingEnum { Poor = 0, Neutral, Good, Excellent };

public class Program
{
    public int ProgramID { get; set; }
    public string ProgramName { get; set; }
    public RatingEnum Rating { get; set; }
    public string ProgramCategory { get; set; }
}
}

//Controller

using System;
using System.Collections.Generic;
using System.Web.Mvc;

namespace MyProgramRatingApp.Controllers
{

public class ProgramController : Controller
{


    List<Program> programList = new List<Program>()
                          {
                            new Program
                            {
                                ProgramID = 1,ProgramName = "Program1",
                                ProgramCategory = "A"
                            },
                            new Program
                            {
                                ProgramID = 2,ProgramName = "Program2",
                                ProgramCategory = "B"
                            },
                            new Program
                            {
                                ProgramID = 3,ProgramName = "Program3",
                                ProgramCategory = "A"
                            }

                          };




    // GET: /Program/
    public ActionResult CastVote()
    {
        ViewBag.RatingEnum = GetRstingSelectList();
        return View(programList);
    }


    // POST: /StoreManager/Create
    [HttpPost]
    public ActionResult CastVote(IEnumerable<Program> theProgramList)
    {
        if (ModelState.IsValid)
        {
            //Save the book in DB first and then redirectToAction.
            return RedirectToAction("CastVote");
        }

        return View(theProgramList);
    }


    public static SelectList GetRstingSelectList()
    {
        Array values = Enum.GetValues(typeof(RatingEnum));
        List<System.Web.UI.WebControls.ListItem> items = new List<System.Web.UI.WebControls.ListItem>(values.Length);

        foreach (var i in values)
        {
            items.Add(new System.Web.UI.WebControls.ListItem
                                    {
                                        Text = Enum.GetName(typeof(RatingEnum), i),
                                        Value = ((int)i).ToString()
                                    }
                       );
        }

        return new SelectList(items);
    }


 }
}

View(CastVote.cshtml)

@model IEnumerable<MyProgramRatingApp.Program>

@{
ViewBag.Title = "CastVote";
}

<h2>CastVote</h2>

@using (Html.BeginForm())
{
<table>
    <tr>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramName
        </th>
        <th style="border:1px solid Teal; background-color:Gray">
            ProgramCategory
        </th>
        <th style="border:1px solid Teal; background-color:Gray">  </th>
    </tr>

    @Html.EditorForModel()

</table>

<p>
    <input type="submit" value="Cast Vote" />
</p>
}

EditorTemplate(Program.cshtml)

@model MyProgramRatingApp.Program
<tr>
<td style="border:1px solid Teal">
    @Html.DisplayFor(x => x.ProgramName)
    @Html.HiddenFor(x => x.ProgramName)
</td>
<td style="border:1px solid Teal">
    @Html.EditorFor(x => x.ProgramCategory)
</td>
<td style="border:1px solid Teal">
    @Html.DropDownListFor(x => x.Rating, (SelectList)ViewBag.RatingEnum, String.Empty)
</td>
<td>
    @Html.HiddenFor(x => x.ProgramID)
</td>

</tr>

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