How It Works
PleaseWaitButton控件在
protected override void Render(HtmlTextWriter output)
{
 // Output the button's html (with attributes)
 // to a dummy HtmlTextWriter
 StringWriter sw = new StringWriter();
 HtmlTextWriter wr = new HtmlTextWriter(sw);
 base.Render(wr);
 string sButtonHtml = sw.ToString();
 wr.Close();
 sw.Close();
 // now modify the code to include an "onclick" handler
 // with our PleaseWait() function called appropriately
 // after any client-side validation.
 sButtonHtml = ModifyJavaScriptonClick(sButtonHtml);
 
 // before rendering the button, output an empty 
// render the button in an encapsulating
 string sReturn = "";
 string sPleaseWaitCode = GeneratePleaseWaitJavascript();
 // is there an existing onclick attribute?
 Regex ronclick = new Regex("onclick=\"(?<onclick>[^\"]*)");
 Match monclick = ronclick.Match(sHtml);
 if (monclick.Success)
 {
 // there is an existing onclick attribute;
 // add our code to the end of it; if client-side
 // validation has been rendered, make sure
 // we check to see if the page is valid;
 string sExisting = monclick.Groups["onclick"].Value;
 string sReplace = sExisting 
 + (sExisting.Trim().EndsWith(";") ? "" : "; ");
 
 if (IsValidatorIncludeScript() && this.CausesValidation)
 {
 // include code to check if the page is valid
 string sCode = "if (Page_IsValid) " + sPleaseWaitCode 
 + " return Page_IsValid;";
 // add our code to the end of the existing onclick code;
 sReplace = sReplace + sCode;
 }
 else
 {
 // don't worry about the page being valid;
 sReplace = sReplace + sPleaseWaitCode;
 }
 // now substitute our onclick code
 sReplace = "onclick=\"" + sReplace;
 sReturn = ronclick.Replace(sHtml, sReplace);
 }
 else
 {
 // there isn't an existing onclick attribute;
 // add ours
 int i = sHtml.Trim().Length - 2;
 string sInsert = " onclick=\"" + sPleaseWaitCode + "\" ";
 sReturn = sHtml.Insert(i, sInsert); 
 }
 
 return sReturn;
}
  这个IsValidatorIncludeScript() 利用上面的检查来查看是否有使用页面注册的asp.net验证控件的标准Javascript代码块。下面则用一个简单的方法测试了是否有验证代码和像Page_IsValid的变量存在。
private bool IsValidatorIncludeScript()
{
 // return TRUE if this page has registered javascript
 // for client-side validation; this code may not be registered
 // if ASP.NET detects what it thinks (correctly or incorrectly)
 // is a down-level browser.
 return this.Page.IsStartupScriptRegistered("ValidatorIncludeScript");
}  下面这个GeneratePleaseWaitJavascript()构建了包含在onclick属性中的PleaseWait() Javascript函数。我们可以通过检查控件的属性来决定想要的布局。
private string GeneratePleaseWaitJavascript()
{
 // create a JavaScript "PleaseWait()" function call
 // suitable for use in an onclick event handler
 string sMessage = "";
 string sText = _pleaseWaitText;
 string sImage = (_pleaseWaitImage != String.Empty 
 ? string.Format(
 ""
 , _pleaseWaitImage, _pleaseWaitText )
 : String.Empty);
 // establish the layout based on PleaseWaitType
 switch (_pleaseWaitType)
 {
 case PleaseWaitTypeEnum.TextThenImage:
 sMessage = sText + sImage;
 break;
 case PleaseWaitTypeEnum.ImageThenText:
 sMessage = sImage + sText;
 break;
 case PleaseWaitTypeEnum.TextOnly:
 sMessage = sText;
 break;
 case PleaseWaitTypeEnum.ImageOnly:
 sMessage = sImage;
 break;
 }
 // return the final code chunk
 string sCode = string.Format(
 "PleaseWait('pleaseWaitButtonDiv_{0}', 
 'pleaseWaitButtonDiv2_{1}', '{2}');"
 , this.ClientID, this.ClientID, sMessage);
 sCode = sCode.Replace("\"", """);
 return sCode;
} 
  如果指定了一个PleaseWaitImage,就必须包含额外的一段Javascript代码来通知客户端预载该图像。这段脚本的注册应该出现在重写的OnPreRender方法中。注册的键是图像的名称;如果多个按钮都使用同一图像,预载脚本只需要实施一次。这里使用了一个正则表达式来创建Javascript图像变量,以保证特殊字字符(比如文件路径中的斜线)转化成下划线。
protected override void OnPreRender(EventArgs e)
{
 base.OnPreRender (e);
 // If we're using an image, register some javascript
 // for client-side image preloading
 if (_pleaseWaitImage != String.Empty 
 && _pleaseWaitType != PleaseWaitTypeEnum.TextOnly)
 RegisterJavascriptPreloadImage(_pleaseWaitImage);
}
private void RegisterJavascriptPreloadImage(string sImage)
{
 Regex rex = new Regex("[^a-zA-Z0-9]");
 string sImgName = "img_" + rex.Replace(sImage, "_"); 
 StringBuilder sb = new StringBuilder();
 sb.Append("");
 this.Page.RegisterClientScriptBlock(sImgName + "_PreloadScript",
 sb.ToString());
}
Client-side functions
嵌入的文本文件javascript.txt包含了隐藏按钮的
protected override void OnInit(EventArgs e)
{
 base.OnInit(e);
 
 // the client-side javascript code is kept
 // in an embedded resource; load the script
 // and register it with the page.
 RegisterJavascriptFromResource();
}
private void RegisterJavascriptFromResource()
{ 
 // load the embedded text file "javascript.txt"
 // and register its contents as client-side script
 string sScript = GetEmbeddedTextFile("javascript.txt");
 this.Page.RegisterClientScriptBlock("PleaseWaitButtonScript", sScript);
}
private string GetEmbeddedTextFile(string sTextFile)
{
 // generic function for retrieving the contents
 // of an embedded text file resource as a string
 // we'll get the executing assembly, and derive
 // the namespace using the first type in the assembly
 Assembly a = Assembly.GetExecutingAssembly();
 String sNamespace = a.GetTypes()[0].Namespace;
 // with the assembly and namespace, we'll get the
 // embedded resource as a stream
 Stream s = a.GetManifestResourceStream(
 string.Format("{0}.{1}", sNamespace, sTextFile)
 );
 
 // read the contents of the stream into a string
 StreamReader sr = new StreamReader(s);
 String sContents = sr.ReadToEnd();
 sr.Close();
 s.Close();
 return sContents;
}
  javascript.txt嵌入资源包含了按钮在Javascript的onclick句柄中执行的客户端方法PleaseWait()。这段代码也调用了一个客户端方法HideDiv()以隐藏按钮的容器
原文链接:http://www.codeproject.com/aspnet/PleaseWaitButton.asp

