MVC 一页多个提交表单(Multi_Form in one page)
前几天遇到同一页有多个提交表单的情况,经过艰苦奋斗终于解决。与大家分享一下。
我的要求有两个:①可以验证显示错误信息②显示错误信息的时候原保留填写的内容
未查找资料之前想了3个解决方案:
①将页面中所有的提交对象封装为一个对象,提交的时候只提交所需要的内容,当有错误信息的时候将已填的内容付给此此对象然后返回它。
优点:可以使用ModelState验证
缺点:如果需要重新写类,如果属性多就很麻烦,重用性低
②页面的对象定为多个form中的一个,其余的使用js验证
优点:可以部分使用ModelState验证
缺点:js使用麻烦需要前台后台写方法,验证麻烦
③建立多个相同的页面,不过页面的对象不同,每个form的对象一个页面,如果有错则转到对象对应的页面。
优点:可以使用ModelState验证
缺点:需要建立多个页面,其实质是转到其他地址。
经过深思熟虑如果第一种改良一下是不错的。
在网上找了半天终于找到与第一种相似的解决方案,不过国家完美。
方法如下:
①扩展HtmlHelper的beginForm 方法,添加一个参数表单名“formName”指定选用哪个Action方法,如下
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc.Html; using System.Web.Mvc; namespace MultiFormTest { public static class HtmlHelperExtession { /// <summary> /// formName /// </summary> /// <param name="htmlHelper"></param> /// <param name="formName">formName</param> /// <returns></returns> public static MvcForm BeginForm(this HtmlHelper htmlHelper, string formName) { return BeginForm(htmlHelper, null, formName); } /// <summary> /// MvcForm form, string formName /// </summary> /// <param name="htmlHelper"></param> /// <param name="form">form</param> /// <param name="formName">formName</param> /// <returns></returns> public static MvcForm BeginForm(this HtmlHelper htmlHelper, MvcForm form, string formName) { if (String.IsNullOrEmpty(formName)) throw new ArgumentNullException("formName"); if (form == null) form = htmlHelper.BeginForm(); htmlHelper.ViewContext.Writer.WriteLine("<input name=\"n.__formName\" type=\"hidden\" value=\"" + formName + "\" />"); return form; } } }
Model对象如下,AccountModel 为页面对象,TestModel 和LogOnModel为form对象,将Form对象作为属性传给页面
public class AccountModel { public TestModel Test { get; set; } public LogOnModel LogOn { get; set; } } public class TestModel { public string MyUserName { get; set; } public string MyEmail { get; set; } public string MyPassword { get; set; } public string MyConfirmPassword { get; set; } } public class LogOnModel { [Required] public string UserName { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } public bool RememberMe { get; set; } }
actionResult 方法,其中"LogOn"和Registertest"表单名
[HttpPost] [FormActionSelector("LogOn")] public ActionResult Index(LogOnModel logOn) { var account = new AccountModel { LogOn = logOn }; return View(account); } [HttpPost] [FormActionSelector("Registertest")] public ActionResult Index(TestModel test) { var account = new AccountModel { Test = test }; return View(account); }
页面代码
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MultiFormTest.AccountModel>" %> <%@ Import Namespace="MultiFormTest" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Home Page </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> <%: ViewData["Message"] %></h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website"> http://asp.net/mvc</a>. </p> <% using (Html.BeginForm("Registertest")) { %> <%: Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.") %> <div> <fieldset> <legend>Account Information</legend> <div class="editor-label"> <%: Html.LabelFor(m => m.Test.MyUserName)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(m => m.Test.MyUserName)%> <%: Html.ValidationMessageFor(m => m.Test.MyUserName)%> </div> <div class="editor-label"> <%: Html.LabelFor(m => m.Test.MyEmail)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(m => m.Test.MyEmail)%> <%: Html.ValidationMessageFor(m => m.Test.MyEmail)%> </div> <div class="editor-label"> <%: Html.LabelFor(m => m.Test.MyPassword)%> </div> <div class="editor-field"> <%: Html.PasswordFor(m => m.Test.MyPassword)%> <%: Html.ValidationMessageFor(m => m.Test.MyPassword)%> </div> <div class="editor-label"> <%: Html.LabelFor(m => m.Test.MyConfirmPassword)%> </div> <div class="editor-field"> <%: Html.PasswordFor(m => m.Test.MyConfirmPassword)%> <%: Html.ValidationMessageFor(m => m.Test.MyConfirmPassword)%> </div> <p> <input type="submit" value="Register" /> </p> </fieldset> </div> <% } %> <% using (Html.BeginForm("LogOn")) { %> <%: Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") %> <div> <fieldset> <legend>Account Information</legend> <div class="editor-label"> <%: Html.LabelFor(m => m.LogOn.UserName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(m => m.LogOn.UserName)%> <%: Html.ValidationMessageFor(m => m.LogOn.UserName)%> </div> <div class="editor-label"> <%: Html.LabelFor(m => m.LogOn.Password)%> </div> <div class="editor-field"> <%: Html.PasswordFor(m => m.LogOn.Password)%> <%: Html.ValidationMessageFor(m => m.LogOn.Password)%> </div> <div class="editor-label"> <%: Html.CheckBoxFor(m => m.LogOn.RememberMe)%> <%: Html.LabelFor(m => m.LogOn.RememberMe)%> </div> <p> <input type="submit" value="Log On" /> </p> </fieldset> </div> <% } %> </asp:Content> HTML代码
<fieldset> <legend>Account Information</legend> <div class="editor-label"> <label for="LogOn_UserName">UserName</label> </div> <div class="editor-field"> <input id="LogOn_UserName" name="LogOn.UserName" type="text" value="admin" /> </div> <div class="editor-label"> <label for="LogOn_Password">Password</label> </div> <div class="editor-field"> <input id="LogOn_Password" name="LogOn.Password" type="password" /> </div> <div class="editor-label"> <input id="LogOn_RememberMe" name="LogOn.RememberMe" type="checkbox" value="true" /><input name="LogOn.RememberMe" type="hidden" value="false" /> <label for="LogOn_RememberMe">RememberMe</label> </div> <p> <input type="submit" value="Log On" /> </p> </fieldset>
可以看到控件的Name 的值是对象.属性(如LogOn.UserName ),MVC识别这种样式,这是我所没想到的
效果:
经测试,有时这种方法得到的对象属性为Null ,不知为什么,很是郁闷,希望大家使用的的话命名等小心一下。不过可以将每个表单做成一个用户控件,控件对象为表单对象就可以避免这个情况。
测试model项目http://u.115.com/file/f1f7377159