一 、實現的效果
我想對於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上。比如上圖所示:Click ”User name is mandatory!”,光標回到User name對應的Texbox。
二、具體實現
現在我們來簡單敘述上面的效果是如果實現的,在開始之前我想說的是,方法非常簡單—或許你已經猜到了:)
1.首先來看看ASPx。


<%

@ 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>


<style type="text/CSS">



body{

}{font-family:Verdana; font-size:10px}


table{

}{width:300px}

table tr{

}{height:30px}


table td.firstColumn{

}{width:100px; text-align:right}


table td.secondColumn{

}{ text-align:left}


table span.asterisk{

}{color:red}


table .textbox{

}{width:150px; border:solid 1px #999999}


table .button{

}{background-color: #00cc66;border:solid 1px #999999}


ul li{

}{margin-bottom:5px}


ul li a{

}{color:red; text-decoration:none}


ul li a:hover{

}{text-decoration:underline}

</style>


<script type="text/Javascript">


function setFocus(control)


{

var controlToValidate = document.getElementById(control);

controlToValidate.focus();

}

</script>

</head>

<body >

<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設置到指定的控件。


<script type="text/Javascript">


function setFocus(control)


{

var controlToValidate = document.getElementById(control);

controlToValidate.focus();

}

</script>
2.接著我們來看看code behind。



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;


public partial class Login : System.Web.UI.Page



{

protected void Page_Load(object sender, EventArgs e)


{

if (this.IsPostBack)

{

return;

}


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!";


this.MakeClickableErrorMessage();

}


private void MakeClickableErrorMessage()


{

foreach (BaseValidator validator in this.Validators)


{

if (validator.ControlToValidate == string.Empty)


{

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;

}

}


protected void ctmUserName_ServerValidate(object source, ServerValidateEventArgs args)


{

if (this.txtUserName.Text.Trim() != "adm")


{

args.IsValid = false;

return;

}


args.IsValid = true;

}

}
Code也簡單得一塌糊塗,除了MakeClickableErrorMessage這個Method,其他的都不值一提。

private void MakeClickableErrorMessage()


{

foreach (BaseValidator validator in this.Validators)

{

if (validator.ControlToValidate == string.Empty)


{

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。