前几天遇到同一页有多个提交表单的情况,经过艰苦奋斗终于解决。与大家分享一下。
我的要求有两个:①可以验证显示错误信息②显示错误信息的时候原保留填写的内容
未查找资料之前想了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