这有点棘手。这是如何解决的。首先将您的_EditBankInfo.cshtml
部分移动到一个看起来像这样的编辑器模板~/Views/Shared/EditorTemplates/BankInfo.cshtml
(注意模板的名称和位置很重要。它应该放在里面~/Views/Shared/EditorTemplates
并命名为您的IEnumerable<T>
集合属性中使用的类型的名称,在您的情况下是BankInfo.cshtml
):
@model BankInfo
<div>
@using (Html.BeginForm())
{
<input type="hidden" name="model.prefix" value="@ViewData.TemplateInfo.HtmlFieldPrefix" />
@Html.HiddenFor(m => m.Id)
@Html.TextBoxFor(m => m.BankAccount)
<button type="submit">Update this stuff</button>
}
</div>
然后在您的主视图中摆脱循环并用对助手foreach
的简单调用替换它:EditorFor
@model ChangeBankAccountViewModel
@Html.EditorFor(x => x.BankInfos)
BankInfos
现在将呈现集合自定义编辑器模板的每个元素。与部分相反,编辑器模板尊重导航上下文并将生成以下标记:
<div>
<form action="/" method="post">
<input type="hidden" name="model.prefix" value="BankInfos[0]" />
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="BankInfos_0__Id" name="BankInfos[0].Id" type="hidden" value="1" />
<input data-val="true" data-val-required="The BankAccount field is required." id="BankInfos_0__BankAccount" name="BankInfos[0].BankAccount" type="text" value="account 1" />
<button type="submit">Update this stuff</button>
</form>
</div>
<div>
<form action="/" method="post">
<input type="hidden" name="model.prefix" value="BankInfos[1]" />
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="BankInfos_1__Id" name="BankInfos[1].Id" type="hidden" value="2" />
<input data-val="true" data-val-required="The BankAccount field is required." id="BankInfos_1__BankAccount" name="BankInfos[1].BankAccount" type="text" value="account 2" />
<button type="submit">Update this stuff</button>
</form>
</div>
...
现在,由于每个字段都有一个特定的名称,因此在发布表单时将不再有任何冲突。model.prefix
请注意我明确放置在每个表单中的隐藏字段。这将被自定义模型绑定器用于该BankInfo
类型:
public class BankInfoModelBinder: DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bindingContext.ModelName = controllerContext.HttpContext.Request.Form["model.prefix"];
return base.BindModel(controllerContext, bindingContext);
}
}
这将在您的Application_Start
:
ModelBinders.Binders.Add(typeof(BankInfo), new BankInfoModelBinder());
好的,现在我们可以开始了。ModelState.Clear
当您不再需要它时,去掉in 您的控制器操作:
[HttpGet]
public ActionResult BankInfo()
{
var model = new ChangeBankAccountViewModel
{
// This is probably populated from some data store
BankInfos = new [] { new BankInfo... },
}
return View(model);
}
[HttpPost]
public ActionResult BankInfo(BankInfo model)
{
if(ModelState.IsValid)
{
// TODO: the model is valid => update its value into your data store
// DO NOT CALL ModelState.Clear anymore.
}
return BankInfo();
}