加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

ASP.NET:创建Linked ValidationSummary, 深入理解ASP.NET的Vali

发布时间:2020-12-16 09:10:38 所属栏目:asp.Net 来源:网络整理
导读:我想对于ASP.NET的Validator控件已经熟悉的不能再熟悉了。我们 已经习惯了用Validator控件来验证我们在表单的输入,并通过ValidationSummary来输出我们为Validator控件设置的Error message。不知道大家有没想过进一步改进一下我们的Validation来改善我们的Us

我想对于ASP.NET的Validator控件已经熟悉的不能再熟悉了。我们 已经习惯了用Validator控件来验证我们在表单的输入,并通过ValidationSummary来输出我们为Validator控件设置的Error message。不知道大家有没想过进一步改进一下我们的Validation来改善我们的User Experience。比如,在ValidationSummary输出一个Link连接到对应的控件,而不是显示单纯的Error message。
比如在上图中,是一个典型的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上。比如上图所示:单击”User name is mandatory!”,光标回到User name对应的Texbox

一、首先来看看aspx

现在我们来简单叙述上面的效果是如果实现的,在开始之前我想说的是,方法非常简单—或许你已经猜到了。下面是上面创建的用于登录的Web页面的HTML。

   1: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
   3: <xmlns="http://www.w3.org/1999/xhtml">
   8:         table{}{width:300px}
  10:         table td.firstColumn{}{width:100px; text-align:right}
  12:         table span.asterisk{}{color:red}
  14:         table .button{}{background-color: #00cc66;border:solid 1px #999999}
  16:         ul li a{}{color:red; text-decoration:none}
  18:    style  19:    
   1:? 
   3:            var controlToValidate = document.getElementById(control);
   5:        } 
   7:    
script 21: head 22: body ="font-family: Verdana" 23: form ="form1" 24: div 25: table cellpadding="0" cellspacing="5px" 26: tr 27: td colspan="2" 28: asp:ValidationSummary ="server" ID="vldLogin" />
  51:                         ="ButtonCancel" ="Cancel" CausesValidation="false"
   1: <script type="text/javascript">
   3:        {
   5:            controlToValidate.focus();
   7: </script>

二、接着我们来看看后台代码

看完了HTML,我们来看看该登录Web页面的后台代码。下面的代码片断为你展示了该Web页面背后的所有代码,所有的机关就存在于Web页面的Load时间处理方法Page_Load方法中。

2: {
   4:     {
   6:         {
   8:         }
  10:         this.rqfUserName.ErrorMessage = string.Format("{0} is mandatory!","User name");
  12:         this.ctmUserName.ErrorMessage = "Such a user has not registered!";
  14:         this.MakeClickableErrorMessage();
  16:? 
  18:     {
  20:         {
  22:             {
  24:             }
  26:             string script = "<a href= "javascript:setFocus('{0}');">{1}</a>",clientID,validator.ErrorMessage);
  28:         }
  30:? 
  32:     {
  34:         {
  36:             return;
  38:? 
  40:     }
   2:     {
   5:                6:             {
   9:               10:               11:             validator.ErrorMessage = script;
  13:     }

在上面的代码中,我遍历page中的每个验证控件。如果该验证具有对应ControlToValidate属性(对于一个验证控件来说,ControlToValidate并非一个必需的属性,如果没有指定该属性,其值为空字符串),直接进入下一个循环。然后我把原来只是弹出的文本转变成一个<a></a>块,然后再将其重新赋值给对应的Validator contorl的ErrorMessage property。比如对于rqfUserName RequiredFieldValidator来说,原来的Error message是”User name is mandatory!”,那么现在的Error message变成了:

>
="Head1"><   4:     Login 
   8:         table{}{width:300px} 
  10:         table td.firstColumn{}{width:100px; text-align:right} 
  12:         table span.asterisk{}{color:red} 
  14:         table .button{}{background-color: #00cc66;border:solid 1px #999999} 
  16:         ul li a{}{color:red; text-decoration:none} 
>    
   6:    
1:
   3: <body style="font-family: Verdana"> 
   5: <div> 
   7: <input type="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /> 
   9: </div> 
  11: <!--
];
  14:         theForm = document.form1;
  16:     function __doPostBack(eventTarget,eventArgument) {
  18:             theForm.__EVENTTARGET.value = eventTarget;
  20:             theForm.submit();
  22:     } 
   1: </script> 
   4:     function WebForm_OnSubmit() {
   6:         true;
   8:    2:         <div> 
   4:                 <tr> 
   6:                         <div id="vldLogin" style="color:Red;display:none;"> 
   8:                     </td> 
  10:                 <tr> 
  12:                         User Name: <span "asterisk">&nbsp;*</span></td> 
  14:                         <input name="txtUserName" type="text" id="txtUserName" "textbox" /> 
  18:                 </tr> 
  20:                     <td "firstColumn"> 
  22:                     <td "secondColumn"> 
  24:                         <span id="rqfPassword" style=  25:                     </td> 
  27:                 <tr> 
  29:                         <input type="submit" name="btnSignIn" value="Sign in" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;btnSignIn&quot;,&quot;&quot;,true,false,false))" id="btnSignIn" "button" />&nbsp;&nbsp;&nbsp; 
  31:                     </td> 
  33:             </table> 
  35: <script type="text/javascript"> 
  37:     var Page_ValidationSummaries = new Array(document.getElementById("vldLogin"));
  39:    2:  
var rqfUserName = document.all ? document.all["rqfUserName"] : document.getElementById("rqfUserName");
   7:     rqfUserName.errormessage = "<a href= "javascript:setFocus('txtUserName');">User name is mandatory!</a>";
   9:     rqfUserName.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
  11:     var ctmUserName = document.all ? document.all["ctmUserName"] : document.getElementById("ctmUserName");
;
var rqfPassword = document.all ? document.all["rqfPassword"] : document.getElementById("rqfPassword");
  18:     rqfPassword.errormessage = "<a href= "javascript:setFocus('txtPassword');">Password is mandatory!</a>";
  20:     rqfPassword.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
   2: <div> 
   4: </div> 
   7:     var Page_ValidationActive =    8:     typeof (ValidatorOnLoad) == "function") {
  10:     }
function ValidatorOnSubmit() {
  14:             return ValidatorCommonOnSubmit();
  16:         else {
  18:         }
  20:   20:         > 

我们从中提取对验证有用的信息。首先我们会看到有两个JavaScript被引用:

"text/javascript"></script>

这两个JavaScript由ASP.NET生成。尤其内容较多,在这里先不列出他们的内容,等下面真正要使用到其中定义的JavaScript 在列出来。我们现在姑且称它们为JavaScript1JavaScript2。在下面一段JavaScript中,为3个验证控件定义了3个客户端的对象,对象的名称和控件名称同名。并设置相关的属性:controltovalidate,errormessage,display,evaluationfunction。其中evaluationfunction为进行Validation的function的名称。

"rqfUserName");
   5:     rqfUserName.errormessage = "<a href= "javascript:setFocus('txtUserName');">User name is mandatory!</a>";
   7:     rqfUserName.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
   9:     "ctmUserName");
;
  14:     "rqfPassword");
  16:     rqfPassword.errormessage = "<a href= "javascript:setFocus('txtPassword');">Password is mandatory!</a>";
  18:     rqfPassword.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
// -->
var Page_ValidationSummaries =  "vldLogin"));
// -->
function WebForm_PostBackOptions(eventTarget,eventArgument,validation,validationGroup,actionUrl,trackFocus,clientSubmit) {
this.eventArgument = eventArgument;
this.validationGroup = validationGroup;
this.trackFocus = trackFocus;
   9: }

该对象具有这样的表述的是关于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中。

var validationResult = true;
   4:         typeof(Page_ClientValidate) == 'function') {
   6:         }
if (validationResult) {
  10:             theForm.action = options.actionUrl;
if (options.trackFocus) {
typeof(lastFocus) != "undefined") && (lastFocus != null)) {
  16:                     lastFocus.value = options.eventTarget;
  18:                 else {
  20:                     typeof(active) != "undefined") && (active !=   21:                         typeof(active.id) != "undefined") && (active.id != null) && (active.id.length > 0)) {
  23:                         }
  25:                             lastFocus.value = active.name;
  27:                     }
  29:             }
  31:     }
  33:         __doPostBack(options.eventTarget,options.eventArgument);
  35: }

在开始的时候,调用Page_ClientValidate进行客户端验证。我们来着重分析上面的javascript,看看具体的流程。Page_ClientValidate被定义在Javascript2中。

2: Page_InvalidControlToBeFocused = null;
var i;
   8:         ValidatorValidate(Page_Validators[i],1)">null);
  10:     ValidatorUpdateIsValid();
  12:     Page_BlockSubmit = !Page_IsValid;
  14: }

上面的代码中,首先通过Page_Validators判断Page是否存在验证控件。我们在预先定义了Page_Validators 数组(还记得我们之前介绍的两个Array——Page_ValidationSummaries和Page_Validators吗?)。虽有遍历所有的验证控件,并调用ValidatorValidate方法执行每个验证控件的客户端验证。我们进一步看看ValidatorValidate又是如何定义的(ValidatorValidate定义在Javascript2中)。

2: val.isvalid = typeof(val.enabled) == "undefined" || val.enabled != false) && IsValidationGroupMatch(val,validationGroup)) {
   5:             val.isvalid = val.evaluationfunction(val);
typeof(val.focusOnError) == "string" && val.focusOnError == "t") {
   9:             }
  11:     }
  13: }

首先通过IsValidationGroupMatch判断验证控件的ValidationGroup是否和触发Postaback的Control对应的ValidationGroup相互匹配。因为只有在匹配的前提下才进行相关验证控件的验证工作。然后调用验证控件的evaluationfunction function来进行验证。通过前面的分析,我们知道RequiredFieldValidator的evaluationfunction为RequiredFieldValidatorEvaluateIsValid,而CustomValidator的evaluationfunction为CustomValidatorEvaluateIsValid。我们来看看这两个function是如何定义的。他们都定义在Javascript2中。

  • RequiredFieldValidatorEvaluateIsValid:通过正则表达式验证是否具有有效输入
    return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) !=       ValidatorTrim(val.initialvalue))
    function ValidatorGetValue(id) {
       6:     control = document.getElementById(id);
       8:         return control.value;
      10:     return ValidatorGetValueRecursive(control);
      12: function ValidatorGetValueRecursive(control)
    "string" && (control.type != "radio" || control.checked == true)) {
      16:     }
      18:     for (i = 0; i<control.childNodes.length; i++) {
    if (val != "") return val;
      22:     "";
      24: function ValidatorTrim(s) {
      26:     return (m == null) ? "" : m[1];
    function CustomValidatorEvaluateIsValid(val) {
    if ((ValidatorTrim(value).length == 0) &&
    true;
    var args = { Value:value,IsValid:true };
      13:     }
      15: }

在ValidatorValidate中,当我们通过调用各个验证控件的evaluationfunction来进行客户端端的验证后,对于没有通过验证的验证控件,通过调用ValidatorSetFocus设置相应控件的焦点。在这里就不在深入探讨了。接着通过调用ValidatorUpdateDisplay来根据我们制定的Display和不同浏览器,来设置错误消息的显示方式。

typeof(val.display) == "string") {
   4:                5:         }
   7:             val.style.display = val.isvalid ? "none" : "inline";
  10:     }
  12:         (navigator.userAgent.indexOf("MSIE") > -1)) {
  15:     val.style.visibility = val.isvalid ? "hidden" : "visible";
function ValidatorUpdateIsValid() {
   3: }
typeof(validators) != "undefined") && (validators != null)) {
if (!validators[i].isvalid) {
  12:     }
  15: function ValidationSummaryOnSubmit(validationGroup) {
var summary,sums,s;
  20:         summary = Page_ValidationSummaries[sums];
  22:         if (!Page_IsValid && IsValidationGroupMatch(summary,validationGroup)) {
  24:             if (summary.showsummary != "False") {
  29:                 switch (summary.displaymode) {
  31:                         headerSep = "<br>";
  35:                         end = break;
default:
  41:                         pre = "<li>";
  43:                         end = "</ul>";
  46:                         headerSep = " ";
  50:                         end = break;
  53:                 s = typeof(summary.headertext) ==   55:                     s += summary.headertext + headerSep;
  57:                 s += first;
  59:                     if (!Page_Validators[i].isvalid && typeof(Page_Validators[i].errormessage) == "string") {
  61:                     }
  63:                 s += end;
  65:                 window.scrollTo(0,0);
  67:             if (summary.showmessagebox == "True") {
  71:                 }
  73:                 for (i=0; i<=lastValIndex; i++) {
  78:                                 if (i < lastValIndex) {
  80:                                 }
  83:                             default:
  85:                                 if (i < lastValIndex) {
  88:                                   89:                               90:                                 s += Page_Validators[i].errormessage +   91:                                   92:                         }
  94:                 }
  96:             }
  98:     }
   5:             args.IsValid =    7:         }