asp.net-mvc – MVC视图中的多个表单:ModelState应用于所有表单

前端之家收集整理的这篇文章主要介绍了asp.net-mvc – 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; }  
}

在我的视图模型中,我希望所有的BankInfos都可以在彼此之间显示,每个表单分开.

要实现这一点,我使用的是部分视图_EditBankInfo:

@model BankInfo

@using (Html.BeginForm())
{
   @Html.HiddenFor(m => m.InvoiceStructureId)
   @Html.TextBoxFor(m => m.IBANAccount)

   <button type="submit">Update this stuff</button>
}

以及我的实际看法BankInfo:

foreach(var info in Model.BankInfos)
{
    Html.RenderPartial("_EditBankInfo",info);
}

最后,这是我的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();
}

所有这些都是工作的hunky dory:验证工作顺利,发布模型得到认可和验证正确…
但是,当页面重新加载时出现问题.
因为我使用相同的表单多次,我的ModelState将被多次应用.所以当在一个表单上执行更新时,下一页加载它们将具有已发布的值.

有什么办法容易防止这种情况发生吗?

我试过这样做,没有部分的意见,但螺丝的命名有点(他们是独一无二的,但服务器模型绑定将不会识别他们).

感谢任何答案.

解决方法

这有点棘手.这是如何解决的.首先将_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 Helper:

@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类型的自定义模型binder使用:

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:

[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();
}

猜你在找的asp.Net相关文章