我有一个MVC控制器,其中post方法上的模型总是返回null。我不确定这是因为我在表单中使用了部分视图。
知道模型没有返回控制器的原因吗?
模型
加载模型
public List<Group> GetStaticMeasures(int businessUnitID)
{
List<Group> groups = ctx.Groups
.Include("Datapoints")
.Where(w => w.BusinessUnitID.Equals(businessUnitID))
.OrderBy(o => o.SortOrder).ToList();
groups.ForEach(g => g.Datapoints = g.Datapoints.OrderBy(d => d.SortOrder).ToList());
return groups;
}
控制器
public ActionResult Data()
{
ViewBag.Notification = string.Empty;
if (User.IsInRole(@"xxx\yyyyyy"))
{
List<Group> dataGroups = ctx.GetStaticMeasures(10);
return View(dataGroups);
}
else
{
throw new HttpException(403, "You do not have access to the data.");
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Data(List<Group> model)
{
ViewBag.Notification = string.Empty;
if (User.IsInRole(@"xxx\yyyyyy"))
{
if (ModelState.IsValid)
{
ctx.SaveChanges(model);
ViewBag.Notification = "Save Successful";
}
}
else
{
throw new HttpException(403, "You do not have access to save the data.");
}
return View(model);
}
主视图
@model List<Jmp.StaticMeasures.Models.Group>
<div class="row">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<div class="large-12">
<div class="large-8 large-centered columns panel">
@foreach (var g in @Model)
{
<h2>@g.Name</h2>
foreach (var d in g.Datapoints)
{
@Html.Partial("Measures", d)
}
<hr />
}
<input type="submit" class="button" value="Save Changes"/>
</div>
</div>
}
</div>
部分视图
@model Jmp.StaticMeasures.Models.Datapoint
@Html.HiddenFor(d => d.ID)
@Html.HiddenFor(d => d.Name)
@Html.HiddenFor(d => d.SortOrder)
@Html.DisplayTextFor(d => d.Name)
@Html.EditorFor(d => d.StaticValue)
@Html.ValidationMessageFor(d => d.StaticValue)
呈现显示连续ID的Html
答案 0 :(得分:13)
正如您所正确指出的那样,这是因为您使用了部分内容。发生这种情况是因为Html.Partial
不知道它正在对集合进行操作,因此它不会为您的表单元素生成名称,而是为了绑定到集合。
但是,您案例中的修复似乎相当简单。您只需将部分更改为Html.Partial
,然后在该模板上调用EditorTemplate
,而不是使用Html.EditorFor
。 Html.EditorFor
非常聪明,可以知道它何时处理集合,因此它将为集合中的每个项调用模板,在表单上生成正确的名称。
为了做你需要的,请按照以下步骤操作:
EditorTemplates
文件夹(例如,如果您的视图为Home\Index.cshtml
,请创建文件夹Home\EditorTemplates
)。该名称很重要,因为它遵循查找模板的惯例。Shared\EditorTemplates
文件夹中。Datapoint.cshtml
(这很重要,因为模板名称基于类型名称的约定)。现在相关的视图代码变为:
// Note: I removed @ from Model here.
@foreach (var g in Model)
{
<h2>@g.Name</h2>
@Html.EditorFor(m => g.DataPoints)
<hr />
}
这可以确保您的视图分离,就像您最初的预期一样。
好吧,正如我在下面提到的,现在的问题是模型绑定器无法将DataPoint
与正确的Group
相关联。简单的解决方法是将视图代码更改为:
for (int i = 0; i < Model.Count; i++)
{
<h2>@Model[i].Name</h2>
@Html.EditorFor(m => m[i].DataPoints)
<hr />
}
这将正确生成名称,并应解决模型绑定问题。
OP的附录
按照John的回答,我还将Group表中缺少的属性包含在HiddenFor中,然后将该模型重新载入帖子。
@for (int i = 0; i < Model.Count(); i++)
{
@Html.HiddenFor(t => Model[i].ID)
@Html.HiddenFor(t => Model[i].BusinessUnitID)
@Html.HiddenFor(t => Model[i].SortOrder)
@Html.HiddenFor(t => Model[i].Name)
<h2>@Model[i].Name</h2>
@Html.EditorFor(m => Model[i].Datapoints)
<hr />
}
我对每个EditorTemplate
使用DataPoint
的建议也适用于每个Group
。您可以通过为for
设置EditorTemplate
,而不是需要Group
循环,再次在视图中显示逻辑。在放置模板的位置方面,上述步骤同样适用。
在这种情况下,模板将为Group.cshtml
,如下所示:
@model Jmp.StaticMeasures.Models.Group
<h2>@Model.Name</h2>
@Html.EditorFor(m => m.DataPoints)
<hr />
如上所述,这将为集合中的每个项调用模板,这也将为每个Group
生成正确的索引。您的原始视图现在可以简化为:
@model List<Jmp.StaticMeasures.Models.Group>
@using (Html.BeginForm())
{
// Other markup
@Html.EditorForModel();
}
答案 1 :(得分:1)
如果像这样返回,Binder无法绑定到对象列表。是的,部分是你的问题。您需要在表单中为ID指定一个数字。
做这样的事情:
// pseudocode
@model List<Jmp.StaticMeasures.Models.Group>
<div class="row">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<div class="large-12">
<div class="large-8 large-centered columns panel">
for(int i; i<Model.Count; i++)
{
<h2>@g.Name</h2>
@Html.HiddenFor(d => Model[i].Id)
@Html.HiddenFor(d => Model[i].Name)
@Html.HiddenFor(d => Model[i].SortOrder)
@Html.DisplayTextFor(d => Model[i].Name)
@Html.EditorFor(d => Model[i].StaticValue)
@Html.ValidationMessageFor(d => Model[i].StaticValue)
<hr />
}
<input type="submit" class="button" value="Save Changes"/>
</div>
</div>
}
</div>
查看有关绑定到Haack's blog
中列表的详细信息答案 2 :(得分:0)
由于模型绑定器处理集合的方式,您将获得空模型。
您的局部视图正在渲染这些输入,例如:
<input type="hidden" name="ID" value="1"/>
...
然后对List<Group>
中的每个条目重复此操作。不幸的是,模型绑定器不知道如何处理它,你将得到一个空值。
您的输入必须看的方式是:
<input type="hidden" name="groups[0].ID" value="1"/>
...
<input type="hidden" name="groups[1].ID" value="2"/>
编号不能中断。获得这个的一种方法是重写你使用Html.xxxFor方法的方式,例如:迭代列表并执行此操作:
@Html.HiddenFor(d => Model[i].Id)
以下是两个资源,详细解释了这一点,并提供了如何使模型绑定器与集合一起使用的其他示例:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/