Jib*_*hew 5 razor asp.net-mvc-3
我想从Razor视图向控制器发布一个项目列表,但我得到一个对象列表为null我的类structre是
模型:
List<Subjects> modelItem
class Subjects
{
int SubId{get;set;}
string Name{get;set;}
List<Students> StudentEntires{get;set;}
}
class StudentEntires
{
int StudId{get;set;}
string Name{get;set;}
int Mark{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
模型本身是一个项目列表,每个项目也包含子项目列表.示例模型是主题列表,每个主题包含学生列表,我想为每个学生输入标记
我的观点就像
@model IList<Subjects>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
if (Model.Count > 0)
{
@for (int item = 0; item < Model.Count(); item++)
{
<b>@Model[item].Name</b><br />
@foreach (StudentEntires markItem in Model[item].StudentEntires)
{
@Html.TextBoxFor(modelItem => markItem.Mark)
}
}
<p style="text-align:center">
<input type="submit" class="btn btn-primary" value="Update" />
</p>
}
}
Run Code Online (Sandbox Code Playgroud)
在控制器中
[HttpPost]
public ActionResult OptionalMarks(int Id,ICollection<Subjects> model)
{
//BUt my model is null. Any idea about this?
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*n H 22
你发现这很困难,因为你没有充分利用MVC框架的全部功能,所以请允许我提供一个有效的例子.
首先,让我们创建一个视图模型来封装视图的数据要求:
public class SubjectGradesViewModel
{
public SubjectGradesViewModel()
{
Subjects = new List<Subject>();
}
public List<Subject> Subjects { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
接下来,创建一个表示主题模型的类:
public class Subject
{
public int Id { get; set; }
public string Name { get; set; }
public List<Student> StudentEntries { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
最后,一个代表学生的班级:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Grade { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
此时,您拥有表示数据所需的所有类.现在让我们创建两个控制器动作,包括一些示例数据,以便您可以看到它是如何工作的:
public ActionResult Index()
{
var model = new SubjectGradesViewModel();
// This sample data would normally be fetched
// from your database
var compsci = new Subject
{
Id = 1,
Name = "Computer Science",
StudentEntries = new List<Student>()
{
new Student { Id = 1, Name = "CompSci 1" },
new Student { Id = 2, Name = "CompSci 2" },
}
};
var maths = new Subject
{
Id = 2,
Name = "Mathematics",
StudentEntries = new List<Student>()
{
new Student { Id = 3, Name = "Maths 1" },
new Student { Id = 4, Name = "Maths 2" },
}
};
model.Subjects.Add(compsci);
model.Subjects.Add(maths);
return View(model);
}
[HttpPost]
public ActionResult Index(SubjectGradesViewModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Success");
}
// There were validation errors
// so redisplay the form
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
现在是构建视图的时候了,这部分在将数据发送回控制器时尤为重要.首先是Index视图:
@model SubjectGradesViewModel
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
@Html.EditorFor(m => m.Subjects) <br />
<input type="submit" />
}
Run Code Online (Sandbox Code Playgroud)
你会注意到我只是在使用Html.EditorFor,同时Subjects作为参数传递.我这样做的原因是因为我们要创建一个EditorTemplate代表一个Subject.我稍后会解释.现在,只知道它EditorTemplates并且DisplayTemplates是MVC中的特殊文件夹名称,因此它们的名称和位置很重要.
我们实际上要创建两个模板:一个用于Subject,一个用于Student.为此,请按照下列步骤操作:
EditorTemplates在视图的当前文件夹中创建一个文件夹(例如,如果您的视图是Home\Index.cshtml,则创建该文件夹Home\EditorTemplates).Subject.cshtml和Student.cshtml分别,(同样,命名很重要)).Subject.cshtml 应该是这样的:
@model Subject
<b>@Model.Name</b><br />
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.Name)
@Html.EditorFor(m => m.StudentEntries)
Run Code Online (Sandbox Code Playgroud)
Student.cshtml 应该是这样的:
@model Student
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.Name)
@Html.DisplayFor(m => m.Name): @Html.EditorFor(m => m.Grade)
<br />
Run Code Online (Sandbox Code Playgroud)
而已.如果您现在构建并运行此应用程序,在POST索引操作上放置断点,您将看到模型已正确填充.
那么,它们EditorTemplates和它们的同行是DisplayTemplates什么?它们允许您创建可重复使用的视图部分,使您可以更多地组织视图.
关于他们的伟大的事情是模板助手,即Html.EditorFor和Html.DisplayFor,有足够的智慧,当他们正在处理一个集合的模板就知道了.这意味着您不再需要遍历项目,每次手动调用模板.您也不必执行任何操作null或Count()检查,因为帮助程序将为您处理所有操作.你留下了干净,没有逻辑的观点.
EditorTemplates当您想要将集合POST到控制器操作时,还会生成适当的名称.这使得模型绑定到列表很多,比自己生成这些名称简单得多.有些时候你仍然需要这样做,但这不是其中之一.
将操作方法签名更改为
public ActionResult OptionalMarks(ICollection<Subjects> model)
因为在你的 HTML 中,看起来没有任何命名的东西Id。但这不是你的主要问题。
接下来,使用 foo 循环执行以下操作
@for(int idx = 0; idx < Model[item].StudentEntires.Count();idx++)
{
@Html.TextBoxFor(_ => Model[item].StudentEntries[idx])
}
Run Code Online (Sandbox Code Playgroud)
可能由于使用了循环foreach,StudentEntries模型绑定器无法将所有内容拼凑在一起,因此返回 NULL。
编辑:
这是一个例子:
控制器
public class HomeController : Controller
{
public ActionResult Index()
{
var viewModel = new IndexViewModel();
var subjects = new List<Subject>();
var subject1 = new Subject();
subject1.Name = "History";
subject1.StudentEntires.Add(new Student { Mark = 50 });
subjects.Add(subject1);
viewModel.Subjects = subjects;
return View(viewModel);
}
[HttpPost]
public ActionResult Index(IndexViewModel viewModel)
{
return new EmptyResult();
}
}
Run Code Online (Sandbox Code Playgroud)
看法
@model SOWorkbench.Controllers.IndexViewModel
@{
ViewBag.Title = "Home Page";
}
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
if (Model.Subjects.Any())
{
int subjectsCount = Model.Subjects.Count();
for (int item = 0; item < subjectsCount; item++)
{
<b>@Model.Subjects[item].Name</b><br />
int studentEntriesCount = Model.Subjects[item].StudentEntires.Count();
for(int idx = 0;idx < studentEntriesCount;idx++)
{
@Html.TextBoxFor(_ => Model.Subjects[item].StudentEntires[idx].Mark);
}
}
<p style="text-align:center">
<input type="submit" class="btn btn-primary" value="Update" />
</p>
}
}
Run Code Online (Sandbox Code Playgroud)
当您发布表单时,您应该看到数据返回到对象中viewModel。
| 归档时间: |
|
| 查看次数: |
20433 次 |
| 最近记录: |