所以我有一个有问题的MVC Asp.net应用程序。基本上,我有一个包含表单的View,其内容绑定到一个对象列表。在这个循环中,它加载PartialView与循环的项目。现在一切正常,直到表格的提交。提交后,控制器将发送一个空对象列表。下面的代码说明了这些问题。
父视图:
@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
@foreach (var planVM in Model)
{
@Html.Partial("_partialView", planVM)
}
</div>
}
_partialView:
@model PlanCompareViewModel
<div>
@Html.HiddenFor(p => p.PlanID)
@Html.HiddenFor(p => p.CurrentPlan)
@Html.CheckBoxFor(p => p.ShouldCompare)
<input type="submit" value="Compare"/>
</div>
这些是上述代码的类:
PlanViewModel:
public class PlansCompareViewModel
{
public int PlanID { get; set; }
public Plan CurrentPlan { get; set; }
public bool ShouldCompare { get; set; }
public PlansCompareViewModel(Plan plan)
{
ShouldCompare = false;
PlanID = plan.PlanId;
CurrentPlan = plan;
}
public PlansCompareViewModel()
{
// TODO: Complete member initialization
}
public static IEnumerable<PlansCompareViewModel> CreatePlansVM(IEnumerable<Plan> plans)
{
return plans.Select(p => new PlansCompareViewModel(p)).AsEnumerable();
}
}
控制器:
public class PlansController : MyBaseController
{
[HttpPost]
public ActionResult ComparePlans(IEnumerable<PlanCompareViewModel> model)
{
//the model passed into here is NULL
}
}
问题出在控制器动作中。据我所知,它应该发布一个可枚举的PlanCompareViewModel列表,但它是null。在检查发送的发布数据时,它正在发送正确的参数。如果我要将'IEnumerable'更改为'FormCollection',它包含正确的值。任何人都可以看到为什么活页夹没有创建正确的对象?我可以使用javascript来解决这个问题,但这会破坏目的!任何帮助将不胜感激!
答案 0 :(得分:90)
您的模型是null
,因为您向表单提供输入的方式意味着模型绑定器无法区分元素。现在,这段代码:
@foreach (var planVM in Model)
{
@Html.Partial("_partialView", planVM)
}
没有为这些项目提供任何类型的索引。所以它会重复生成这样的HTML输出:
<input type="hidden" name="yourmodelprefix.PlanID" />
<input type="hidden" name="yourmodelprefix.CurrentPlan" />
<input type="checkbox" name="yourmodelprefix.ShouldCompare" />
但是,由于您希望绑定到集合,因此需要使用索引命名表单元素,例如:
<input type="hidden" name="yourmodelprefix[0].PlanID" />
<input type="hidden" name="yourmodelprefix[0].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[0].ShouldCompare" />
<input type="hidden" name="yourmodelprefix[1].PlanID" />
<input type="hidden" name="yourmodelprefix[1].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[1].ShouldCompare" />
该索引使模型绑定器能够关联单独的数据,从而允许它构建正确的模型。所以这就是我建议你做的修复它。而不是使用局部视图循环您的集合,而是利用模板的强大功能。以下是您需要遵循的步骤:
EditorTemplates
文件夹(例如,如果您的视图为Home\Index.cshtml
,请创建文件夹Home\EditorTemplates
)。PlanCompareViewModel.cshtml
。现在,您在局部视图中拥有的所有内容都希望进入该模板:
@model PlanCompareViewModel
<div>
@Html.HiddenFor(p => p.PlanID)
@Html.HiddenFor(p => p.CurrentPlan)
@Html.CheckBoxFor(p => p.ShouldCompare)
<input type="submit" value="Compare"/>
</div>
最后,您的父视图简化为:
@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
@Html.EditorForModel()
</div>
}
DisplayTemplates
和EditorTemplates
非常聪明,可以知道他们何时处理集合。这意味着它们将自动为表单元素生成正确的名称,包括索引,以便您可以正确地将绑定模型化为集合。
答案 1 :(得分:29)
请阅读:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
您应该为html元素“name”属性设置标记,例如planCompareViewModel[0].PlanId
,planCompareViewModel[1].PlanId
,以使binder能够将它们解析为IEnumerable。
而不是@foreach (var planVM in Model)
使用for
循环并使用索引呈现名称。