一 、实现的效果
我想对于ASP.NET的Validator控件已经熟悉的不能再熟悉了。我们 已经习惯了用Validator控件来验证我们在表单的输入,并通过ValidationSummary来输出我们为Validator控件设置的Error message。不知道大家有没想过进一步改进一下我们的Validation来改善我们的User Experience。比如,在ValidationSummary输出一个Link连接到对应的控件,而不是显示单纯的Error message。
![](https://images.cnblogs.com/cnblogs_com/artech/validation_01_06.JPG)
比如在上图中,是一个典型的Login的Page。我们有两个必填的字段:User name和Password。为此我定义两个RequiredFieldValidator。他们的Error message分别为:”User name is mandatory!”和”Password is mandatory!”。在未输入任何值得前提下Click “Sign in”按钮,Error Message被显示在ValidationSummary上面。不过和传统的Error message不同,显示在ValidationSummary上的实际上是两个链接,Click对应的Error message,光标会设置到对应的Textbox上。比如上图所示:Click ”User name is mandatory!”,光标回到User name对应的Texbox。
二、具体实现
现在我们来简单叙述上面的效果是如果实现的,在开始之前我想说的是,方法非常简单—或许你已经猜到了:)
1.首先来看看aspx。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Login</title>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<style type="text/css">![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
body{
}{font-family:Verdana; font-size:10px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table{
}{width:300px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table tr{
}{height:30px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table td.firstColumn{
}{width:100px; text-align:right}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table td.secondColumn{
}{ text-align:left}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table span.asterisk{
}{color:red}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table .textbox{
}{width:150px; border:solid 1px #999999}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table .button{
}{background-color: #00cc66;border:solid 1px #999999}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li{
}{margin-bottom:5px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li a{
}{color:red; text-decoration:none}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li a:hover{
}{text-decoration:underline}
</style>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
function setFocus(control)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
var controlToValidate = document.getElementById(control);
controlToValidate.focus();
}
</script>
</head>
<body style="font-family: Verdana">
<form id="form1" runat="server">
<div>
<table cellpadding="0" cellspacing="5px">
<tr>
<td colspan="2">
<asp:ValidationSummary runat="server" ID="vldLogin" />
</td>
</tr>
<tr>
<td class="firstColumn">
User Name: <span class="asterisk"> *</span></td>
<td class="secondColumn">
<asp:TextBox runat="server" ID="txtUserName" CssClass="textbox"></asp:TextBox>
<asp:RequiredFieldValidator runat="server" ID="rqfUserName" ControlToValidate="txtUserName" Display="None"></asp:RequiredFieldValidator>
<asp:CustomValidator runat="server" ID="ctmUserName" Display="None" OnServerValidate="ctmUserName_ServerValidate" ControlToValidate="txtUserName" ></asp:CustomValidator>
</td>
</tr>
<tr>
<td class="firstColumn">
Password: <span class="asterisk"> *</span></td>
<td class="secondColumn">
<asp:TextBox runat="server" ID="txtPassword" TextMode="Password" CssClass="textbox"></asp:TextBox>
<asp:RequiredFieldValidator runat="server" ID="rqfPassword" ControlToValidate="txtPassword" Display="None" ></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<asp:Button runat="server" ID="btnSignIn" Text="Sign in" CssClass="button" />
<asp:Button runat="server" ID="ButtonCancel" Text="Cancel" CausesValidation="false"
CssClass="button" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
在看到了上面的Screen shot之后再看看上面的Html,结构清晰得一目了然。所以我就不再进一步解释了。在这里我只需要提提定义在aspx的一段javascript function:setFocus。通过它把focus设置到指定的控件。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
function setFocus(control)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
var controlToValidate = document.getElementById(control);
controlToValidate.focus();
}
</script>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2.接着我们来看看code behind。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public partial class Login : System.Web.UI.Page
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
protected void Page_Load(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (this.IsPostBack)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.rqfUserName.ErrorMessage = string.Format("{0} is mandatory!", "User name");
this.rqfPassword.ErrorMessage = string.Format("{0} is mandatory!", "Password");
this.ctmUserName.ErrorMessage = "Such a user has not registered!";
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.MakeClickableErrorMessage();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void MakeClickableErrorMessage()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (BaseValidator validator in this.Validators)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (validator.ControlToValidate == string.Empty)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
continue;
}
string clientID = this.FindControl(validator.ControlToValidate).ClientID;
string script = string.Format("<a href= \"javascript:setFocus('{0}');\">{1}</a>", clientID, validator.ErrorMessage);
validator.ErrorMessage = script;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
protected void ctmUserName_ServerValidate(object source, ServerValidateEventArgs args)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (this.txtUserName.Text.Trim() != "adm")
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
args.IsValid = false;
return;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
args.IsValid = true;
}
}
Code也简单得一塌糊涂,除了MakeClickableErrorMessage这个Method,其他的都不值一提。
private void MakeClickableErrorMessage()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
foreach (BaseValidator validator in this.Validators)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (validator.ControlToValidate == string.Empty)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
continue;
}
string clientID = this.FindControl(validator.ControlToValidate).ClientID;
string script = string.Format("<a href= \"javascript:setFocus('{0}');\">{1}</a>", clientID, validator.ErrorMessage);
validator.ErrorMessage = script;
}
}
显示在ValidationSummary中原本简单的literal error message就是通过上面的这个MakeClickableErrorMessage转变成hyperlink的。在上面的code中,我遍历page中的每个Validator control。如果该Validator control有对应ControlToValidate(对于一个Validator control来说,ControlToValidate并非一个必需的property,如果没有指定该property,其值为空字符串),直接进入下一个循环。然后我把原来只是弹出的文本转变成一个<a></a>,然后再将其重新赋值给对应的Validator contorl的ErrorMessage property。
比如对于rqfUserName RequiredFieldValidator来说,原来的Error message是”User name is mandatory!”,那么现在的Error message变成了:
<a href=”javascript: setFocus(‘txtUserName’);”> User name is mandatory!</a>
三、ASP.NET是如何实现Validation的
上面只是一个简单的小窍门,我们以这个Sample为例,来进一步介绍ASP.NET如何尽心Validation的。为了简单起见,在这里我没法讨论所有的Validator control。只介绍RequiredFieldValidator和CustomValidator这两种Validator control的处理流程。
1.Client side Validation
我们通过IE来浏览上面的Page,通过参看Source code,可以看到最后Render出来的html:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title>
Login
</title>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<style type="text/css">![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
body{
}{font-family:Verdana; font-size:10px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table{
}{width:300px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table tr{
}{height:30px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table td.firstColumn{
}{width:100px; text-align:right}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table td.secondColumn{
}{ text-align:left}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table span.asterisk{
}{color:red}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table .textbox{
}{width:150px; border:solid 1px #999999}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
table .button{
}{background-color: #00cc66;border:solid 1px #999999}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li{
}{margin-bottom:5px}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li a{
}{color:red; text-decoration:none}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ul li a:hover{
}{text-decoration:underline}
</style>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
function setFocus(control)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
var controlToValidate = document.getElementById(control);
controlToValidate.focus();
}
</script>
</head>
<body style="font-family: Verdana">
<form name="form1" method="post" action="Login.aspx" onsubmit="javascript:return WebForm_OnSubmit();" id="form1">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTg3OTM1NTM2MA9kFgICAw9kFgYCBQ8PFgIeDEVycm9yTWVzc2FnZQVKPGEgaHJlZj0gImphdmFzY3JpcHQ6c2V0Rm9jdXMoJ3R4dFVzZXJOYW1lJyk7Ij5Vc2VyIG5hbWUgaXMgbWFuZGF0b3J5ITwvYT5kZAIHDw8WAh8ABVI8YSBocmVmPSAiamF2YXNjcmlwdDpzZXRGb2N1cygndHh0VXNlck5hbWUnKTsiPlN1Y2ggYSB1c2VyIGhhcyBub3QgcmVnaXN0ZXJlZCE8L2E+ZGQCCw8PFgIfAAVJPGEgaHJlZj0gImphdmFzY3JpcHQ6c2V0Rm9jdXMoJ3R4dFBhc3N3b3JkJyk7Ij5QYXNzd29yZCBpcyBtYW5kYXRvcnkhPC9hPmRkZLFuksmAaQ+N5sw8K+rkFk3GqgSn" />
</div>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var theForm = document.forms['form1'];
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!theForm)
{
theForm = document.form1;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
function __doPostBack(eventTarget, eventArgument)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!theForm.onsubmit || (theForm.onsubmit() != false))
{
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// -->
</script>
<script src="/Artech.ClickableValidationSummary/WebResource.axd?d=07ZNXubMk-rxUjn0jMywXg2&t=632969324944906146" type="text/javascript"></script>
<script src="/Artech.ClickableValidationSummary/WebResource.axd?d=5q3WmDnqxzNvEfUc_QbMe5qdQO1LUQ4P7mwuv6CrIMk1&t=632969324944906146" type="text/javascript"></script>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
function WebForm_OnSubmit()
{
if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
return true;
}
// -->
</script>
<div>
<table cellpadding="0" cellspacing="5px">
<tr>
<td colspan="2">
<div id="vldLogin" style="color:Red;display:none;">
</div>
</td>
</tr>
<tr>
<td class="firstColumn">
User Name: <span class="asterisk"> *</span></td>
<td class="secondColumn">
<input name="txtUserName" type="text" id="txtUserName" class="textbox" />
<span id="rqfUserName" style="color:Red;display:none;"></span>
<span id="ctmUserName" style="color:Red;display:none;"></span>
</td>
</tr>
<tr>
<td class="firstColumn">
Password: <span class="asterisk"> *</span></td>
<td class="secondColumn">
<input name="txtPassword" type="password" id="txtPassword" class="textbox" />
<span id="rqfPassword" style="color:Red;display:none;"></span>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" name="btnSignIn" value="Sign in" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("btnSignIn", "", true, "", "", false, false))" id="btnSignIn" class="button" />
<input type="submit" name="ButtonCancel" value="Cancel" id="ButtonCancel" class="button" />
</td>
</tr>
</table>
</div>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var Page_ValidationSummaries = new Array(document.getElementById("vldLogin"));
var Page_Validators = new Array(document.getElementById("rqfUserName"), document.getElementById("ctmUserName"), document.getElementById("rqfPassword"));
// -->
</script>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var rqfUserName = document.all ? document.all["rqfUserName"] : document.getElementById("rqfUserName");
rqfUserName.controltovalidate = "txtUserName";
rqfUserName.errormessage = "<a href= \"javascript:setFocus(\'txtUserName\');\">User name is mandatory!</a>";
rqfUserName.display = "None";
rqfUserName.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
rqfUserName.initialvalue = "";
var ctmUserName = document.all ? document.all["ctmUserName"] : document.getElementById("ctmUserName");
ctmUserName.controltovalidate = "txtUserName";
ctmUserName.errormessage = "<a href= \"javascript:setFocus(\'txtUserName\');\">Such a user has not registered!</a>";
ctmUserName.display = "None";
ctmUserName.evaluationfunction = "CustomValidatorEvaluateIsValid";
var rqfPassword = document.all ? document.all["rqfPassword"] : document.getElementById("rqfPassword");
rqfPassword.controltovalidate = "txtPassword";
rqfPassword.errormessage = "<a href= \"javascript:setFocus(\'txtPassword\');\">Password is mandatory!</a>";
rqfPassword.display = "None";
rqfPassword.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
rqfPassword.initialvalue = "";
// -->
</script>
<div>
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWBQL7uOMiAqXVsrMJArWptJELAsP3i5QHAv23gdwNI0m2v8hOJGGPTPLYqDLAkZE0nKU=" />
</div>
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var Page_ValidationActive = false;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(ValidatorOnLoad) == "function")
{
ValidatorOnLoad();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
function ValidatorOnSubmit()
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (Page_ValidationActive)
{
return ValidatorCommonOnSubmit();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
return true;
}
}
// -->
</script>
</form>
</body>
</html>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
我们从中提取对Validation有用的信息。
首先我们会看到有两个JavaScript被引用:
<script src="/Artech.ClickableValidationSummary/WebResource.axd?d=07ZNXubMk-rxUjn0jMywXg2&t=632969324944906146" type="text/javascript"></script>
<script src="/Artech.ClickableValidationSummary/WebResource.axd?d=5q3WmDnqxzNvEfUc_QbMe5qdQO1LUQ4P7mwuv6CrIMk1&t=632969324944906146" type="text/javascript"></script>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
这两个JavaScript由ASP.NET生成。尤其内容较多,在这里先不列出他们的内容,等下面真正要使用到其中定义的JavaScript 在列出来。我们现在姑且称它们为JavaScript1和JavaScript2。
在下面一段JavaScript中,为3个Validator control定义了3个Client端的对象,对象的名称和控件名称同名,并设置相关的属性:controltovalidate,errormessage,display,evaluationfunction。其中evaluationfunction为进行Validation的function的名称.
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var rqfUserName = document.all ? document.all["rqfUserName"] : document.getElementById("rqfUserName");
rqfUserName.controltovalidate = "txtUserName";
rqfUserName.errormessage = "<a href= \"javascript:setFocus(\'txtUserName\');\">User name is mandatory!</a>";
rqfUserName.display = "None";
rqfUserName.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
rqfUserName.initialvalue = "";
var ctmUserName = document.all ? document.all["ctmUserName"] : document.getElementById("ctmUserName");
ctmUserName.controltovalidate = "txtUserName";
ctmUserName.errormessage = "<a href= \"javascript:setFocus(\'txtUserName\');\">Such a user has not registered!</a>";
ctmUserName.display = "None";
ctmUserName.evaluationfunction = "CustomValidatorEvaluateIsValid";
var rqfPassword = document.all ? document.all["rqfPassword"] : document.getElementById("rqfPassword");
rqfPassword.controltovalidate = "txtPassword";
rqfPassword.errormessage = "<a href= \"javascript:setFocus(\'txtPassword\');\">Password is mandatory!</a>";
rqfPassword.display = "None";
rqfPassword.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
rqfPassword.initialvalue = "";
// -->
</script>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
我们还发现通过Javascript定义了两个Array对象:Page_ValidationSummaries和Page_Validators。这两个Array用于保存Page中的所有的ValidationSummary和Validator control。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<script type="text/javascript">![](https://www.cnblogs.com/Images/dot.gif)
<!--
var Page_ValidationSummaries = new Array(document.getElementById("vldLogin"));
var Page_Validators = new Array(document.getElementById("rqfUserName"), document.getElementById("ctmUserName"), document.getElementById("rqfPassword"));
// -->
</script>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
我们知道,所有的Validation操作都是在Click “Sign In” Button之后进行的。我们来看看,他是如何定义的:
<input type="submit" name="btnSignIn" value="Sign in" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("btnSignIn", "", true, "", "", false, false))" id="btnSignIn" class="button" />
通过onclick事件,我们可以看到,一个命名为WebForm_DoPostBackWithOptions的javascript function被调用,该function接收一个称为WebForm_PostBackOptions类型的对象。该类型被定一个在JavaScript1中(还记得JavaScript1指的是什么吗? 上溯到第三段)。下面是他的定义:
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function WebForm_PostBackOptions(eventTarget, eventArgument, validation, validationGroup, actionUrl, trackFocus, clientSubmit)
{
this.eventTarget = eventTarget;
this.eventArgument = eventArgument;
this.validation = validation;
this.validationGroup = validationGroup;
this.actionUrl = actionUrl;
this.trackFocus = trackFocus;
this.clientSubmit = clientSubmit;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
该对象具有这样的表述的是关于Postback context的一些信息,比如:
-
eventTarget:Event触发的control,当前为” btnSignIn”。
-
eventArgument:Event额外的参数, 当前为””。
-
validation:是否进行Validation,当前为true。
-
validationGroup:eventTarget 对应的Validation group,这是ASP.NET 2.0的新特性,当当前为””,因为我没有设置btnSignIn的ValidationGroup的property。
-
actionUrl:表单被提交的Url,就像asp中Form的action一样。ASP.NET 1.x不提供cross-page的提交,在2.0中提供了此功能,当前为””, 我没有进行cross-page的提交。
-
trackFocus:是否进行焦点追踪,当前为false。
-
clientSubmit:是否通过form submit导致Postback,当前为false。
我们再来看看WebForm_DoPostBackWithOptions,像WebForm_PostBackOptions一样,该function同样被定义在JavaScript1中。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function WebForm_DoPostBackWithOptions(options)
{
var validationResult = true;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (options.validation)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(Page_ClientValidate) == 'function')
{
validationResult = Page_ClientValidate(options.validationGroup);
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (validationResult)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(options.actionUrl) != "undefined") && (options.actionUrl != null) && (options.actionUrl.length > 0))
{
theForm.action = options.actionUrl;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (options.trackFocus)
{
var lastFocus = theForm.elements["__LASTFOCUS"];
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(lastFocus) != "undefined") && (lastFocus != null))
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(document.activeElement) == "undefined")
{
lastFocus.value = options.eventTarget;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
var active = document.activeElement;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(active) != "undefined") && (active != null))
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(active.id) != "undefined") && (active.id != null) && (active.id.length > 0))
{
lastFocus.value = active.id;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else if (typeof(active.name) != "undefined")
{
lastFocus.value = active.name;
}
}
}
}
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (options.clientSubmit)
{
__doPostBack(options.eventTarget, options.eventArgument);
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
在开始的时候,调用Page_ClientValidate进行Client端的Validation。在这里执行所有的Client端的Validation。我们来着重分析上面的javascript,看看具体的流程。Page_ClientValidate被定义在Javascript2中。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function Page_ClientValidate(validationGroup)
{
Page_InvalidControlToBeFocused = null;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(Page_Validators) == "undefined")
{
return true;
}
var i;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i = 0; i < Page_Validators.length; i++)
{
ValidatorValidate(Page_Validators[i], validationGroup, null);
}
ValidatorUpdateIsValid();
ValidationSummaryOnSubmit(validationGroup);
Page_BlockSubmit = !Page_IsValid;
return Page_IsValid;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
上面的code中,首先通过Page_Validators判断是否Page中定义了Validator control。我们在预先定义了Page_Validators Array(还记得我们之前介绍的两个Array——Page_ValidationSummaries和Page_Validators吗?)。虽有遍历所有的Validator control,并调用ValidatorValidate方法执行每个Validator control的Client端的Validation。我们进一步看看ValidatorValidate又是如何定义的(ValidatorValidate定义在Javascript2中):
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidatorValidate(val, validationGroup, event)
{
val.isvalid = true;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(val.enabled) == "undefined" || val.enabled != false) && IsValidationGroupMatch(val, validationGroup))
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(val.evaluationfunction) == "function")
{
val.isvalid = val.evaluationfunction(val);
if (!val.isvalid && Page_InvalidControlToBeFocused == null &&
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
typeof(val.focusOnError) == "string" && val.focusOnError == "t")
{
ValidatorSetFocus(val, event);
}
}
}
ValidatorUpdateDisplay(val);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
首先通过IsValidationGroupMatch判断Validator control的ValidationGroup是否和触发Postaback的Control对应的ValidationGroup相互匹配。因为只有在匹配的前提下才进行相关Validator control的validation。然后调用validator control的evaluationfunction function来进行validation。通过前面的分析,我们知道RequiredFieldValidator的evaluationfunction为RequiredFieldValidatorEvaluateIsValid,而CustomValidator的evaluationfunction为CustomValidatorEvaluateIsValid。我们来看看这两个function是如何定义的。他们都定义在Javascript2中。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function RequiredFieldValidatorEvaluateIsValid(val)
{
return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) != ValidatorTrim(val.initialvalue))
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidatorGetValue(id)
{
var control;
control = document.getElementById(id);
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(control.value) == "string")
{
return control.value;
}
return ValidatorGetValueRecursive(control);
}
function ValidatorGetValueRecursive(control)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(control.value) == "string" && (control.type != "radio" || control.checked == true))
{
return control.value;
}
var i, val;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i = 0; i<control.childNodes.length; i++)
{
val = ValidatorGetValueRecursive(control.childNodes[i]);
if (val != "") return val;
}
return "";
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidatorTrim(s)
{
var m = s.match(/^\s*(\S+(\s+\S+)*)\s*$/);
return (m == null) ? "" : m[1];
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function CustomValidatorEvaluateIsValid(val)
{
var value = "";
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(val.controltovalidate) == "string")
{
value = ValidatorGetValue(val.controltovalidate);
if ((ValidatorTrim(value).length == 0) &&
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
((typeof(val.validateemptytext) != "string") || (val.validateemptytext != "true")))
{
return true;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
var args =
{ Value:value, IsValid:true };
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(val.clientvalidationfunction) == "string")
{
eval(val.clientvalidationfunction + "(val, args) ;");
}
return args.IsValid;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
在ValidatorValidate中,当我们通过调用各个Validator control的evaluationfunction来进行Client端的验证后,对于没有通过验证的Validator control,通过调用ValidatorSetFocus设置相应控件的焦点。在这里就不在深入探讨了。接着通过调用ValidatorUpdateDisplay来根据我们制定的Display和不同浏览器,来设置Error message的显示方式。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidatorUpdateDisplay(val)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(val.display) == "string")
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (val.display == "None")
{
return;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (val.display == "Dynamic")
{
val.style.display = val.isvalid ? "none" : "inline";
return;
}
}
if ((navigator.userAgent.indexOf("Mac") > -1) &&
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
(navigator.userAgent.indexOf("MSIE") > -1))
{
val.style.display = "inline";
}
val.style.visibility = val.isvalid ? "hidden" : "visible";
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
实际上到现在为止,所有的Validation工作已经完成。我们来看看Error message是如何显示的。所以我们要看看ValidatorUpdateDisplay的定义了。
分析完ValidatorValidate,我们在回到Page_ClientValidate上面。现在我们接着分析一下的执行流程。通过调用ValidatorValidate执行完各个Validator control的验证后,接着调用的是ValidatorUpdateIsValid()和ValidationSummaryOnSubmit(validationGroup)。ValidatorUpdateIsValid通过遍历每个Validator control来查看他们是否通过验证,最终确定这个Page是否通过验证。ValidationSummaryOnSubmit通过拼接字符串的形式在ValidationSummary显示对应的Error message。这正是我们可我们Error message写成hyperlink的原因所在。
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidatorUpdateIsValid()
{
Page_IsValid = AllValidatorsValid(Page_Validators);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function AllValidatorsValid(validators)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((typeof(validators) != "undefined") && (validators != null))
{
var i;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i = 0; i < validators.length; i++)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!validators[i].isvalid)
{
return false;
}
}
}
return true;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
function ValidationSummaryOnSubmit(validationGroup)
{
if (typeof(Page_ValidationSummaries) == "undefined")
return;
var summary, sums, s;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (sums = 0; sums < Page_ValidationSummaries.length; sums++)
{
summary = Page_ValidationSummaries[sums];
summary.style.display = "none";
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!Page_IsValid && IsValidationGroupMatch(summary, validationGroup))
{
var i;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (summary.showsummary != "False")
{
summary.style.display = "";
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(summary.displaymode) != "string")
{
summary.displaymode = "BulletList";
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
switch (summary.displaymode)
{
case "List":
headerSep = "<br>";
first = "";
pre = "";
post = "<br>";
end = "";
break;
case "BulletList":
default:
headerSep = "";
first = "<ul>";
pre = "<li>";
post = "</li>";
end = "</ul>";
break;
case "SingleParagraph":
headerSep = " ";
first = "";
pre = "";
post = " ";
end = "<br>";
break;
}
s = "";
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(summary.headertext) == "string")
{
s += summary.headertext + headerSep;
}
s += first;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i=0; i<Page_Validators.length; i++)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!Page_Validators[i].isvalid && typeof(Page_Validators[i].errormessage) == "string")
{
s += pre + Page_Validators[i].errormessage + post;
}
}
s += end;
summary.innerHTML = s;
window.scrollTo(0,0);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (summary.showmessagebox == "True")
{
s = "";
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (typeof(summary.headertext) == "string")
{
s += summary.headertext + "\r\n";
}
var lastValIndex = Page_Validators.length - 1;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i=0; i<=lastValIndex; i++)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!Page_Validators[i].isvalid && typeof(Page_Validators[i].errormessage) == "string")
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
switch (summary.displaymode)
{
case "List":
s += Page_Validators[i].errormessage;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (i < lastValIndex)
{
s += "\r\n";
}
break;
case "BulletList":
default:
s += "- " + Page_Validators[i].errormessage;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (i < lastValIndex)
{
s += "\r\n";
}
break;
case "SingleParagraph":
s += Page_Validators[i].errormessage + " ";
break;
}
}
}
alert(s);
}
}
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2 Server side Validation
前面我们花了很大的篇幅介绍了Client端的Validation,通过介绍我们知道了,Client端的validation和Error message的显示均由Javascript来完成。现在我们来简单看看Server 端的Validation。当client 端__doPostBack被调用实现向Server端的Postback。具体的Postback可以参考我的文章:浅谈ASP.NET的Postback。Validator Contro 的Server端的Validation,Error message直接通过Html显示出来。
比如下面是一段CustomValidator的Validation。
protected void ctmUserName_ServerValidate(object source, ServerValidateEventArgs args)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
if (this.txtUserName.Text.Trim() != "adm")
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
args.IsValid = false;
return;
}
args.IsValid = true;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
如果上面的Validation没有通过,最终render在client段的将有下面一段Html。
![](https://images.cnblogs.com/cnblogs_com/artech/validation_01_04.JPG)
![](https://images.cnblogs.com/cnblogs_com/artech/validation_01_05.JPG)