【发布时间】:2015-03-01 05:19:13
【问题描述】:
我正在开展一个项目,使用 ASP.NET MVC 5 帮助学生和顾问选择下学期的最佳课程。第一步是让学生从列表中选择他已经学习过的课程。显示列表的控制器是:
public ActionResult AddCourseVM (int? id)
{
Student student = db.Students.Find(id);
// List<BaseCourse> potentialCourses = student.StudentConcentration.RequiredCourses.ToList();
List<BaseCourse> potentialCourses = db.BaseCourses.ToList();
AddCourseViewModel vModel = new AddCourseViewModel(student, potentialCourses);
List<Course> listCourses = new List<Course>();
foreach(BaseCourse baseC in potentialCourses)
{
Course c = new Course();
c.BaseCourse = baseC;
c.Student = student;
listCourses.Add(c);
}
vModel.PossibleCourses = listCourses;
return View("AddCourseVM", vModel);
}
ViewModel 是:
public class AddCourseViewModel
{
public Student Student { get; set; }
public List<BaseCourse> AvailCourses { get; set; }
public List<Course> PossibleCourses { get; set; }
public AddCourseViewModel(Student s, List<BaseCourse> c)
{
Student = s;
AvailCourses = c;
PossibleCourses = new List<Course>();
}
public AddCourseViewModel()
{
Student = new Student();
AvailCourses = new List<BaseCourse>();
PossibleCourses = new List<Course>();
}
}
Course 对象是课程的特定实例(对于给定的学生,在某个学期等),BaseCourse 对象是课程目录中的各个课程。
我正在使用此视图在列表中显示可能的课程:
@model CMPSAdvising.ViewModels.AddCourseViewModel
@{
ViewBag.Title = "AddCourseVM";
}
<h2>Add Courses</h2>
<div>
<p>Name: @Model.Student.FirstName @Model.Student.LastName</p>
<p>W#: @Model.Student.WNumber</p>
</div>
<div>
<p>Select the Courses You Have Taken</p>
</div>
<div>
@using (Html.BeginForm("AddCourseVM","Students"))
{
@Html.AntiForgeryToken();
<div>
<table class="table table-bordered">
<tr>
<th>Course</th>
<th>Department</th>
<th>Number</th>
<th>Check if Taken</th>
<th>Semester</th>
<th>Grade</th>
</tr>
@foreach (var course in Model.PossibleCourses)
{
<tr>
<td>@course.BaseCourse.Name</td>
<td>@course.BaseCourse.CourseNumber</td>
<td>@course.BaseCourse.CourseNumber</td>
<td>@Html.CheckBoxFor(s => course.Selected)</td>
<td>@Html.TextBoxFor(m => course.Semester)</td>
<td>@Html.TextBoxFor(g => course.Grade)</td>
</tr>
}
</table>
<input type="submit" value="Save Classes Taken" class="btn btn-default" />
</div>
}
</div>
最后是当用户点击按钮时接收 POST 的控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddCourseVM (AddCourseViewModel vModel)
{
Student stu = vModel.Student;
foreach (Course c in vModel.PossibleCourses)
{
if (c.Selected)
{
stu.CoursesTaken.Add(c);
}
}
db.Entry(stu).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("ListTakenCourses", new { id = stu.ID });
}
我的问题是 AddCourseViewModel 对象 (vModel) 返回 null。我想从网页中获取 ViewModel 作为对象,或者至少获取已检查的课程列表和学生 ID。
【问题讨论】:
-
您在 cshtml 中的
foreach导致 razor 在由CheckBoxFor、TextBoxFor生成的 HTML 中输出与AddCourseViewModel操作参数不匹配的name属性。默认模型绑定器无法确定应该如何将这些输入名称解析为动作参数模型。查看 razor 输出生成的实际 HTML,并将表单元素名称属性与操作参数类的属性名称进行比较。 -
好的,我查看了 html,它们都有 name="course.Selected"。例如,如果我使用特定课程的 ID 为每个复选框创建唯一名称,我如何收集这些名称并将它们发送回控制器?或者有没有我想念的更好的方法?
-
您需要了解的细节可以在这里找到:haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
-
还要注意属性名对应
foreach循环中的变量名。如果您将其更改为@foreach (var pCrs in Model.PossibleCourses),您会看到属性名称更改为name="pCrs.Selected"。您可能需要尝试类似 BeginCollectionItem 的帮助:nuget.org/packages/BeginCollectionItem
标签: c# asp.net asp.net-mvc mvvm