Kip*_*pie 12 asp.net-mvc modelstate
在单个视图上遇到多个表单的问题.
假设我有以下viewmodel:
public class ChangeBankAccountViewModel
{
public IEnumerable<BankInfo> BankInfos { get; set; }
}
public class BankInfo
{
[Required]
public string BankAccount { get; set; }
public long Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在我的viewmodel中,我希望所有BankInfos都显示在彼此之下,每个都在单独的表单中.
为实现这一点,我正在使用局部视图_EditBankInfo:
@model BankInfo
@using (Html.BeginForm())
{
@Html.HiddenFor(m => m.InvoiceStructureId)
@Html.TextBoxFor(m => m.IBANAccount)
<button type="submit">Update this stuff</button>
}
Run Code Online (Sandbox Code Playgroud)
以及我的实际观点BankInfo:
foreach(var info in Model.BankInfos)
{
Html.RenderPartial("_EditBankInfo", info);
}
Run Code Online (Sandbox Code Playgroud)
最后,这是我的2个动作方法:
[HttpGet]
public ActionResult BankInfo()
{
return View(new ChangeBankAccountViewModel{BankInfos = new [] {new BankInfo...});
}
[HttpPost]
public ActionResult BankInfo(BankInfo model)
{
if(ModelState.IsValid)
ModelState.Clear();
return BankInfo();
}
Run Code Online (Sandbox Code Playgroud)
所有这一切都是工作hunky dory:验证工作顺利,发布模型得到正确识别和验证...但是,当页面重新加载时问题出现.因为我多次使用相同的表单,我的ModelState将被多次应用.因此,当在一个表单上执行更新时,下一页加载所有表单将具有已发布的值.
有没有办法轻易防止这种情况发生?
我尝试过没有部分视图的做法,但这有点搞砸了命名(它们是唯一的,但是服务器端模型绑定将无法识别它们).
谢谢你的回答.
Dar*_*rov 10
这有点棘手.这是如何解决的.首先将您的_EditBankInfo.cshtml
partial 移动到一个~/Views/Shared/EditorTemplates/BankInfo.cshtml
看起来像这样的编辑器模板(注意模板的名称和位置很重要.它应放在内部~/Views/Shared/EditorTemplates
并命名为您的IEnumerable<T>
collection属性中使用的typed的名称,在您的情况下是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>
Run Code Online (Sandbox Code Playgroud)
然后在你的主视图中摆脱foreach
循环并用一个简单的调用EditorFor
帮助器替换它:
@model ChangeBankAccountViewModel
@Html.EditorFor(x => x.BankInfos)
Run Code Online (Sandbox Code Playgroud)
现在,对于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>
...
Run Code Online (Sandbox Code Playgroud)
现在,由于每个字段都有一个特定的名称,因此在发布表单时不再存在任何冲突.注意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);
}
}
Run Code Online (Sandbox Code Playgroud)
将在您的注册Application_Start
:
ModelBinders.Binders.Add(typeof(BankInfo), new BankInfoModelBinder());
Run Code Online (Sandbox Code Playgroud)
好的,现在我们很高兴.ModelState.Clear
在您不再需要它时,摆脱控制器中的操作:
[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();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5447 次 |
最近记录: |