??xml version="1.0" encoding="utf-8" standalone="yes"?> Scott Mitchell 2003 q?8 ?/p>
适用于:(x) 前提条gQ?/b>本文假设读者熟(zhn)?ASP.NET?/p>
隑ֺQ?/b> 2 摘要Q?/b>管从技术角度讲QASP.NET 服务器控件的所有功能都可以在服务器端执行,但通常情况下通过d客户端脚本可以大大增强服务器控g的可用性。本文将探讨服务器控件发送客L(fng)脚本的两U方法,q将构徏两个使用q些技术的服务器控Ӟ(x) 下蝲 InjectingClientSideScript.msi?/p>
?/a> 管从技术角度讲QMicrosoft] ASP.NET
服务器控件的所有功能都可以在服务器端执行,但通常情况下通过d客户端脚本可以大大增强服务器控g的可用性。例如,ASP.NET 验证 Web
控g可以在服务器端执行所有的验证查。但是,对于高版本浏览器Q验?Web
控g也会(x)发送客L(fng)脚本Q以在客L(fng)q行验证。这是_(d)q些览器的用户可以获得响应效果更好的动态体验?/p>
在开?ASP.NET 服务器控件时Q?zhn)不妨问问自己Q如何才能通过使用客户端脚本来增强可用性。一旦找到可行的Ҏ(gu)Q其他要做的是增强服务器控件的功能Q以使其发送合适的客户端脚本?/p>
ASP.NET 服务器控件可以发送两U客L(fng)脚本Q?/p>
客户端脚本块通常是用 JavaScript ~写的,其中通常包含在发生特定的客户端事件时执行的函数。客L(fng) HTML 属性提供将客户端事件与客户端脚本联pd一L(fng)Ҏ(gu)。例如,以下?HTML 面中包含了客户端脚本块Q脚本块中包含了名ؓ(f) ?1 是单几ZClick Me!”按钮时 HTML 面的屏q快照?/p>
?1Q单几ZClick Me!”按钮时昄的弹出式对话?/b> 对于以上 HTML 面中的客户端脚本,有几点值得注意。首先,客户端脚本块包含?HTML 注释Q?code><!-- ? 如果(zhn)对客户端脚本不是很熟?zhn)Qalert(string) 函数的作用就是显CZ个模式弹出式对话框,对话框中包含的消息由 string 参数指定。所?HTML 元素都有若干个可以绑定一D客L(fng) JavaScript 代码的客L(fng)属性(例如Q?code>onclick?code>onmouseover?code>onmouseout?code>onfocus ? 在本文中Q我们将学习(fn)如何?ASP.NET 服务器控件中发送客L(fng)脚本块和 HTML 元素属性。我们首先讨论如何? System.Web.UI.Page cd含的两个Ҏ(gu)可以客L(fng)脚本代码发送到?ASP.NET Web 面提供?HTML 中:(x) q两个方法都接受两个字符串作入。第二个参数 script 是要插入到页面中的客L(fng)脚本Q包? q两个方法唯一的不同之处在于从“何处”发送脚本块?code>RegisterClientScriptBlock() ?Web H体的开始处Q紧接着 Z么会(x)有两U不同的Ҏ(gu)来发送客L(fng)脚本Q要更好C解这一点,我们必须首先了解Q客L(fng)脚本可以分ؓ(f)两类Q一cL在加载页面后立即q行的代码,
一cL在发生某些客L(fng)事g时才q行的代码。前者的常见CZ是将焦点讄到文本框的客L(fng)代码。例如,当?zhn)讉K Google
Ӟ在页面加载后׃(x)执行一段客户端代码,以自动将焦点讄到搜索文本框?/p>
以下是后一cM码(为响应客L(fng)事g而运行的代码Q的CZ。具体而言Q在该示例中Q单?yn)L钮时显CZ个弹出式对话框:(x) 在这D代码中Q?code><input> 标记中的 相反Q以?HTML 不会(x)焦点设|到文本框,因ؓ(f)文本框是在脚本块“之后”定义的Q?/p> 因此Q?code>RegisterStartupScript() Ҏ(gu)? ? 如上所qͼ在? 要了解如何用这两个Ҏ(gu)Q可以看一?ASP.NET 验证 Web 控gQ如 RequiredFieldValidator、RegularExpressionValidator {等。这些控仉?x)用C个常用的验证 JavaScript 文g ( 接下来要考虑的是Q如果一?ASP.NET Web 面中包含多个验?Web 控gQ会(x)出现什么情况呢Q所有这?Web 控g都要使用相同的关键字发送相同的脚本块。如果用这个关键字调用两次 q时应该? 因此Q每ơ构建客L(fng)脚本Ӟ应该首先调用 误住, 通常Q添加客L(fng)脚本块这个Q务会(x)使用 让我们创Z个只昄客户端弹出式对话框的 ASP.NET 服务器控件。此CZ说明构Z个发送客L(fng)脚本的控件是很容易的?/p>
首先Q在 Microsoft] Visual Studio] .NET 中创Z个新?Web Control LibraryQWeb 控g库)目。这创Z个只有一个类的新目Q这个类? 大多数内|的 ASP.NET 服务器控仉?x)发送一?HTML 元素。例如,TextBox Web 控g发送一? 既然我们要创建的服务器控件不可见Q它只是发送一个显C弹出式控g的客L(fng)脚本块)Q这个控件最好从 q个控g只需要两个属性:(x) 除了q两U属性之外,我们需要覆? 误住下面两件事Q首先, 在注册脚本块之前Q代码首先检查三个条Ӟ(x) 如果满q三个条Ӟ则脚本被指定Qƈ? PopupGreeting 代码可以从本文结֤提供的下载中获得。该下蝲包括名ؓ(f) ClientSideControlsAndTester ?Visual Studio .NET 解决Ҏ(gu)Q其中包含两个项目:(x) ClientSideControls 目~译后的E序集名? ?2 昄?PopupGreeting 控gd?ToolboxQ工L(fng)Qƈd到设计器后,Visual Studio .NET
的屏q快照。ToolboxQ工L(fng)Q中?PopupGreeting 控g用红色线圈出Q设计器中的 PopupGreeting
输出用蓝色线圈出Q在屏幕快照右侧的“Properties”(属性)H格中可以查?PopupGreeting 的属性?/p>
?2QPopupGreeting 服务器控件已d?ASP.NET Web H体面 如上所qͼ有两U方法可以通过服务器控件发送客L(fng)脚本Q?/p>
在上一节中Q我们探讨了如何使用 在开始之前,h意这U方法通常只适用于从 Zq用该信息,我们创徏一个作为确认按钮的服务?Web
控g。确认按钮是一U提交按钮,当用户单?yn)L按钮Ӟ显CZ个弹出式对话框,询问用户是否定要l操作。用户可以单几Z取消”,不提交窗体。此功?
对用于删除信息的按钮特别有用Q因为最l用P或网站管理员Q可能会(x)在无意中单击鼠标删除数据库中的条目,如果没有Z(x)取消Q将是非o(h)人烦恼的事?/p>
Z减少工作量,我们? 首先Q在 Visual Studio .NET 中创Z个新?Web Control LibraryQWeb 控g库)目Q或者在
ClientSideControls 目中添加一个新?Web Custom ControlQWeb
自定义控Ӟ。ConfirmButton cȝ完整源代码如下所C:(x) 首先要注意的是, 我们只需覆盖一个方法,? 如果(zhn)不熟?zhn)?JavaScript ? ?3Q操作中?ConfirmButton ConfirmButton 在按钮的 在本文中Q我们探讨了两种通过 ASP.NET 服务器控件插入客L(fng)脚本的方法。第一U方法是使用 Page cȝ 我们q在文中介绍了两个简单的服务器控Ӟ它们都利用了客户端脚本来改进其功能。PopupGreeting 控g在页面首ơ加载时昄一个模式弹出式对话框,ConfirmButton Web 控g在用户单?yn)L钮提交表单时Q提C用戯行确认?/p>
(zhn)可以在自己的服务器控g中插入客L(fng)脚本Q这显著改善用户体验。本文提供的两个服务器控件相Ҏ(gu)较简单,在可用性和独创性上没有什么突Z处?a >MetaBuilders.com
中展CZ很多利用?ASP.NET 服务器控件中插入客户端脚本而实现的功能Q这些功能会(x)l?zhn)留下深刻印象。在
MetaBuilders.comQ?zhn)可以扑ֈ一些服务器控gQ它们有的可以自动将焦点d到文本框Q有的可以在两个下拉列表之间传递条目,有的可以向下
拉列表中d或删除条目,q有的可以在一pd下拉列表中显C父子关pȝ数据Q等{。最大的好处是,q些控g是免费的Qƈ包括完整的源代码?/p>
大家编E快乐! Scott Mitchell 著有五本关于 ASP/ASP.NET 的书c,?4GuysFromRolla.com
|站的创始hQ过Mq来一直从?Microsoft Web 技术方面的研究。Scott ?ASP ?ASP.NET
C非常z跃的一名成员,十分热爱 ASP ?ASP.NET 技术,q常愿意帮助其他h了解q些令h振奋的技术。有?
DataGrid、DataList ?Repeater 控g的详l信息,请参?Scott 的著作《ASP.NET Data Web
Controls Kick Start》(ISBN ?0672325012Q?/p>
Microsoft] ASP.NETPopupGreeting
Q一个在首次加蝲?Web 面上显C带有特定消息的客户端模式对话框的服务器控gQ?code class="ce">ConfirmButtonQ一个增强的 Button Web 控gQ如果用L(fng)?yn)L按钮Q则在发?Web H体前向用户昄一?JavaScript confirm()
的对话框。(本文包含一些指向英文站点的链接。)目录
使用 RegisterStartupScript() ?RegisterClientScriptBlock() d客户端脚本块
探讨 IsStartupScriptRegistered() ?IsClientScriptBlockRegistered()
?ASP.NET 服务器控件发送客L(fng)脚本?/a>
发?ASP.NET 服务?Web 控g?HTML 属?/a>
结doClick()
的函数。该面同时q包含一个按钮(通过 <input>
HTML 元素创徏Q,q个按钮?onclick
属性与 doClick()
函数l定。也是_(d)只要用户单击该按钮,开始执?doClick()
函数中的客户端代码。在本示例中Q将昄一个弹出式对话框(?1Q?/p><html>
<body>
<form>
<script language="JavaScript">
<!--
function doClick() {
alert("You clicked me!");
}
// -->
</script>
<input type="button" onclick="doClick()" value="Click Me!" />
</form>
</body>
</html>-->
Q中。之所以这P是因为如果不脚本块攑օ HTML 注释中,那些不能识别脚本的旧式浏览器׃(x)昄 <script>
块的内容。此外,q要注意Q脚本块?HTML 注释的结束标记前有一?JavaScript 注释Q即 //
。这是因为旧版本?Netscape 在遇?-->
Ӟ?x)抛?JavaScript 分析异常Q因此必d其注释掉。幸q的是,C的浏览器已不需要这一额外操作Q所以在?Intranet 或其他由览器控制的环境开?Web 面Ӟ(zhn)就不必采取此类预防措施了?/p>
onblur
{等Q。例如,在上面的 HTML 面中,<input>
元素?onclick
属性绑定到 doClick()
函数Q因此在单击该按钮时执?doClick()
函数。有?JavaScript 事g及其兌?HTML 属性的列表Q请参阅 Introduction to Dynamic HTML 一文。有兛_L(fng) JavaScript 的详l信息,请参?HTML and Dynamic HTML 一文?/p>
System.Web.UI.Page
cM的两个方法来?ASP.NET Web 面d客户端脚本块Q这两个Ҏ(gu)?RegisterStartupScript()
?RegisterClientScriptBlock()
?
掌握q一知识后,我们构Z个简单的服务器控Ӟ让这个控件在每次加蝲面时显CZ个客L(fng)弹出式对话框。之后,我们再来了解如何?HTML
属性添加到 ASP.NET 服务器控件的 HTML 元素。最后,我们归Ux有知识,实际构徏一?ConfirmButton Web
控gQ当单击q个控gӞ向用户提示一个对话框Q询问用h否要l箋?/p>使用 RegisterStartupScript() ?RegisterClientScriptBlock() d客户端脚本块
<script>
的v始标记和l止标记。第一个参?key 是插入的客户端脚本的唯一标识W?/p>
<form runat="server">
标识之后Q发送脚本块Q?RegisterStartupScript()
?Web H体的结֤Q在 </form>
标识之前Q发送脚本块?/p>
<html>
<body>
<form>
<script language="JavaScript">
<!--
function displayPopup() {
alert("Hello, world.");
}
// -->
</script>
<input type="button" value="Click Me!" onclick="displayPopup()" />
</form>
</body>
</html>onclick="displayPopup()"
用于指明在单?yn)L钮时QJavaScript 函数 displayPopup()
应该q行?/p>
RegisterStartupScript()
Ҏ(gu)可用于添加要在加载页面后q行的脚本块。通过q种Ҏ(gu)d的脚本块位于 Web H体的结֤Q因为必d脚本q行前定义脚本要修改?HTML
元素。也是_(d)如果(zhn)要使用客户端脚本将焦点讄到文本框Q必ȝ保文本框?HTML 标记位于讄该文本框的焦点的脚本之前。例如,下面?
HTML 显CZ个文本框Qƈ焦点设|到该文本框Q?/p><input type="text" id="myTextBox" />
<script language="JavaScript">
<!--
document.getElementById("myTextBox").focus();
// -->
</script><script language="JavaScript">
<!--
document.getElementById("myTextBox").focus();
// -->
</script>
<input type="text" id="myTextBox" /><script>
块置?Web H体的结֤Q以保证在执行客L(fng)脚本之前已声?Web H体中的所?HTML 元素?/p>
RegisterClientScriptBlock()
Ҏ(gu)用于为响应客L(fng)事g而执行的脚本代码。通过此方法发送的脚本块位?Web 面的开始处Q因U方法不要求脚本块|于所?HTML 元素之后?/p>探讨 IsStartupScriptRegistered() ?IsClientScriptBlockRegistered()
RegisterStartupScript()
?RegisterClientScriptBlock()
Ҏ(gu)之外Q?code>Page c还包含两个在发送客L(fng)脚本时常用的辅助Ҏ(gu)Q?/p>
RegisterStartupScript()
?RegisterClientScriptBlock()
插入客户端脚本块Ӟ提供了一个唯一标识脚本块的关键字。这两个Ҏ(gu)都接受一个输入(字符?keyQ,q返回一个布?yu)(dng)|以指C带有指定关键字的脚本块是否已添加到面中。具体地_(d)如果带有特定 key 的脚本块已经注册Q这些方法将q回 TrueQ否则将q回 False?/p>
WebValidation.js
)Q该文g位于 ASP.NET Web 应用E序?aspnet_client/system_web/版本?/i>
目录中。因此,所有这些控仉?x)发送相同的脚本块,q个脚本块将调用?WebValidation.js
文g中定义的相应?JavaScript 函数Q以启动客户端的验证q程。要完成q个q程Q这些控件会(x)使用 Page
cȝ RegisterClientScriptBlock()
Ҏ(gu)Qƈ使用关键?ValidatorIncludeScript
?/p>
RegisterClientScriptBlock()
?RegisterStartupScript()
Ҏ(gu)Q则W二ơ调用会(x)被认为是复制脚本块而被忽略。因此,即一?Web 面上有多个验证控gQ也只是发送一个公p本块的实例。但是,h意,除第一个控件之外的其他所有验?Web 控g都会(x)构徏要发送的公共客户端脚本,而这只是在浪Ҏ(gu)间?/p>
IsClientScriptBlock()
?IsStartupScript()
Ҏ(gu)。这样一来,验证 Web 控g׃?x)先花时间构发送的客户端代码,而是先检查是否已l存在用关键字 ValidatorIncludeScript
注册的脚本。如果存在,控g׃(x)攑ּ构徏客户端脚本块Q因本块已经由页面上的其他验证控件构Z?/p>
IsClientScriptBlock()
?IsStartupScript()
Ҏ(gu)Q以定是否需要生成客L(fng)脚本。在下面一节,我们看C些示例,在这些示例中Q?code>IsClientScriptBlock()?code>IsStartupScript() Ҏ(gu)先后?RegisterClientScriptBlock()
?RegisterStartupScript()
Ҏ(gu)l合使用?/p>?ASP.NET 服务器控件发送客L(fng)脚本?/font>
RegisterStartupScript()
?RegisterClientScriptBlock()
Ҏ(gu)?System.Web.UI.Page
cȝҎ(gu)。幸q的是,可以Ҏ(gu)C ASP.NET 服务器控件调用这两个Ҏ(gu)Q因?System.Web.UI.Control
c(所?ASP.NET 服务器控仉直接或间接地从这个类导出Q有一个包含对 Page
实例的引用的 Page
属性,而这?Page
实例包含服务器控件。因此,要从 ASP.NET 服务器控件添加客L(fng)脚本块,(zhn)只需使用下面的语法:(x)this.Page.RegisterClientScriptBlock(key, script);
OnPreRender()
Ҏ(gu)来处理,q个Ҏ(gu)在控件生命周期的预呈现阶D|行?/p>
System.Web.UI.WebControls.WebControl
导出。但是,我们希望q个cM System.Web.UI.Control
cd出。ؓ(f)什么呢Q因?WebControl
cȝ于支持显CZؓ(f) HTML 元素的服务器控gQ?Control
cd用于不会(x)昄?HTML 元素的服务器控g?/p>
<input>
元素Q其cd属性设|ؓ(f) textQDataGrid Web 控g发送一?<table>
元素Qؓ(f)每条要显C的记录发?<tr>
元素Qؓ(f)每个字段发?<td>
列。但是,不是所有的控g都需要发?HTML 元素。例如,Literal 控g只是按原栯出它?Text 属性,而不这个属性放?HTML
元素中。同PRepeater 也不其输出攑֜ HTML 元素中。那些显CZؓ(f) HTML 元素的服务器控gQ如
TextBox、Button、DataGrid {等Q是?System.Web.UI.WebControls.WebControl
cd出的Q而那?b>?/b>产生 HTML 元素的控Ӟ?Literal、Repeater {,是从 System.Web.UI.Control
cd出的?/p>
System.Web.UI.Control
导出Q而不是从 System.Web.UI.WebControls.WebControl
导出?/p>
PopupMessage
- 表示要在弹出式对话框中显C的消息的字W串?
Enabled
- 表示是否启用控g的布?yu)(dng)倹{如果启用控Ӟ则显C弹出式对话框,否则不显C。(必须d一?Enabled
属性,是因为导控g?Control
cM包括 Enabled
属性,此属性只是隐含地由那些从 WebControl
导出的控件用。)OnPreRender()
Ҏ(gu)。在q里Q我们需要调?RegisterStartupScript()
Qƈ传递控件唯一的关键字和恰当的客户端脚本以昄弹出式对话框。这个类的完整代码如下所C:(x)using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace ClientSideScript
{
/// <summary>
/// WebCustomControl1 的摘要描q?br> /// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}opupGreeting runat=server></{0}
opupGreeting>")]
public class PopupGreeting : System.Web.UI.Control
{
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string PopupMessage
{
get
{
// ?ViewState 中是否存在该目
object popupMessage = this.ViewState["PopupMessage"];
if (popupMessage != null)
return this.ViewState["PopupMessage"].ToString();
else
return "Welcome to my Web site!";
}
set
{
// 指定 ViewState 变量
ViewState["PopupMessage"] = value;
}
}
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public bool Enabled
{
get
{
// ?ViewState 中是否存在该目
object enabled = this.ViewState["Enabled"];
if (enabled != null)
return (bool) this.ViewState["Enabled"];
else
return true;
}
set
{
// 指定 ViewState 变量
ViewState["Enabled"] = value;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender;
string scriptKey = "intoPopupMessage:" + this.UniqueID;
if (!Page.IsStartupScriptRegistered(scriptKey) && this.Enabled &&
!Page.IsPostBack)
{
string scriptBlock =
@"<script language=""JavaScript"">
<!--
alert(""%%POPUP_MESSAGE%%"");
// -->
</script>";
scriptBlock = scriptBlock.Replace("%%POPUP_MESSAGE%%", this.PopupMessage);
Page.RegisterStartupScript(scriptKey, scriptBlock);
}
}
}
}Enabled
?PopupMessage
属性保存在 ViewState
中,q样在回传时q些值可以始l保持一_(d) 其次Q在 OnPreRender()
Ҏ(gu)中,用于脚本块的关键字是文本 intoPopupMessage:
加上控g?UniqueID
属性。如果用一个硬~码的关键字Q则当页面中有多个控件时Q只有第一个控件能够注册其脚本块,因此只显CZ个弹出式对话框。通过在脚本块关键字中使用 UniqueID
Q就能保证该控g的每个实例都能获取其脚本块?/p>
IsStartupScriptRegistered()
Ҏ(gu)Q然后再花时间创建和注册启动脚本?
PopupMessage
属性D插入到脚本中适当的位|。最后,调用 Page
属性的 RegisterStartupScript()
Ҏ(gu)Q传入关键字及脚本代码?/p>
ClientSideControls.dll
。要在?zhn)自己?ASP.NET Web 应用E序中?PopupGreeting 服务器控Ӟ请将 ClientSideControls.dll
文gd到?zhn)?Web 应用E序的引用中。然后,在设计器中,右键单击 ToolboxQ工L(fng)Qƈ选择“Add/Remove Items . . .”(d/删除)Q再ơ选择 ClientSideControls.dll
文g。这样就?ToolboxQ工L(fng)Q中d了名?PopupGreeting 的新V然后,(zhn)可以从 ToolboxQ工L(fng)Q将该控件拖到设计器中?/p>
Page
cȝ RegisterStartupScript()
?RegisterClientScriptBlock()
Ҏ(gu)?ASP.NET Web 面d客户端脚本块。在最后这一节,我们了解如何?HTML 元素属性添加到服务器控件的 HTML 元素?/p>
System.Web.UI.WebControls.WebControl
cd出的服务器控Ӟ因ؓ(f)从这个类导出的控件会(x)发送某?HTML 元素。不发?HTML 元素的服务器控gQ如上一节中?PopupGreeting 服务器控ӞQ则不必写出 HTML 元素属性,因ؓ(f)q些控gq行时不?x)写?HTML 元素?/p>
WebControl
cd含一个将 HTML 元素属性添加到?Web 控g发出?HTML 元素的方法。该Ҏ(gu)UCؓ(f) AddAttributesToRender()
Q它只有一个输入参敎ͼ?HtmlTextWriter
的实例。要?Web 控gd HTML 属性,(zhn)可以?HtmlTextWriter
的以下两个方法之一Q?/p>
AddAttribute()
Ҏ(gu)用于?title
?code>class?code>style ?onclick
{?HTML 属性添加到 HTML 元素?code>AddStyleAttribute() 用于样式设|添加到 HTML 元素Q如 background-color
?code>color ?font-size
{?/p>
AddAttribute()
有几个重载窗体,但在代码中,我们用以下窗体:(x)AddAttribute(HtmlTextWriterAttribute, value)
。第一个参敎ͼ?HtmlTextWriterAttributeQ应该是 HtmlTextWriterAttribute
枚D的成员。该枚D包含?Align
?code>Bgcolor?code>Class ?Onclick
{项。?zhn)可以?.NET Framework Class LibraryQ?a >HtmlTextWriterAttribute Enumeration 中找到完整的列表?i>value 输入参数用于指定分配l特?HTML 属性的倹{最后,如果(zhn)想d一?HtmlTextWriterAttribute
枚D中未定义?HTML 属性,可以使用 AddAttribute()
Ҏ(gu)的替代Ş?AddAttribute(attributeName, value)
Q其中的 attributeName ?value 均ؓ(f)字符丌Ӏ?/p>
System.Web.UI.WebControls.Button
cM导出 ConfirmButton Web 控gQ因个类本n已完成了涉及呈现提交按钮的所有繁重工作。在导出的类中,我们只需d一个属性,q样用户可以指定认消息Q然后覆盖按钮的 AddAttributesToRender()
Ҏ(gu)Qƈd一个属性以处理客户端事?onclick
?/p>
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace ClientSideControls
{
/// <summary>
/// ConfirmButton 的摘要描q?br> /// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:ConfirmButton runat=server></{0}:ConfirmButton>")]
public class ConfirmButton : Button
{
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string PopupMessage
{
get
{
// ?ViewState 中是否存在该目
object popupMessage = this.ViewState["PopupMessage"];
if (popupMessage != null)
return this.ViewState["PopupMessage"].ToString();
else
return "Are you sure you want to continue?";
}
set
{
// 指定 ViewState 变量
ViewState["PopupMessage"] = value;
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
string script = @"return confirm(""%%POPUP_MESSAGE%%"");";
script = script.Replace("%%POPUP_MESSAGE%%",
this.PopupMessage.Replace("\"", "\\\""));
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, script);
}
}
}ConfirmButton
cL?Button
cd出的。由?Button cd包含 Button Web 控g使用的所有属性和Ҏ(gu)Q因此我们所做的只是d属性和Ҏ(gu)Q以在用户单?yn)L钮时昄一个确认对话框。现在我们需要一个属性,?PopupMessage
Q?
它是要在认弹出式对话框中显C的消息。默认情况下Q这条消息是“Are you sure you want to
continue?”((zhn)确定要l箋吗?Q如果?ConfirmButton 来确认删除,可能需要将该消息更改ؓ(f)“This action
will permanently delete the selected item. Are you sure you want to do
this?”(此操作将怹删除所选项。?zhn)定要l吗Q)AddAttributesToRender()
。在此方法中Q我们只要构建当触发 <input>
元素?onclick
事g时要执行的客L(fng) JavaScriptQ然后通过传入?HtmlTextWriter
对象?AddAttribute()
Ҏ(gu)dq段 JavaScript。关于这个方法,有一点要注意Q必d PopupMessage
属性g的所有双引号实例替换{义双引号Q即 \"
Q。另外还要注意,默认情况下,AddAttribute()
?x)对W二个参C的字W进?HTML ~码。也是_(d)ASP.NET Web 面中如果包?PopupMessage
属性被讄为“Do you want to continue?”(要l吗Q)?ConfirmButtonQ该面发送以?HTML 标记Q?/p><input type="submit" name="ConfirmButton1"
value="Click Me!" id="ConfirmButton1" onclick="return confirm
("Do you want to continue?"" />
confirm(string)
函数Q那么请(zhn)注意,该函数只接受一个字W串参数Qƈ昄一个带有特定字W串的模式对话框。该对话框中包含两个按钮Q“确定”和“取消”。如果单几Z确定”,confirm()
函数q回 TrueQ否则返?False。请注意Q?code>onclick 事g返?confirm()
函数调用的结果。当通过单击提交按钮来提交表单时Q如果提交按钮的 onclick
事gq回 FalseQ则表单未被提交。因此,只有在用L(fng)认后Q可以?confirm()
函数提交表单。有?confirm()
的详l信息,请参?ASP Warrior |站中的 Javascript Confirm Form Submission?/p>
onclick
事g处理E序中用了内嵌?JavaScriptQ还可以?ConfirmButton ?OnPreRender()
Ҏ(gu)的客L(fng)脚本块中创徏一个函敎ͼ然后调整 onclick
属性以调用该函数?/p>结
RegisterStartupScript()
?RegisterClientScriptBlock()
Ҏ(gu)插入客户端脚本块。第二种Ҏ(gu)是向 HTML 元素的属性添加客L(fng)脚本。后者通过覆盖 Web 服务器控件的 AddAttributesToRender()
Ҏ(gu)Qƈ使用 HtmlTextWriter
?AddAttribute()
Ҏ(gu)来完成?/p>
作者简?/h4>
推荐链接Q?/h4>
Wintellect
2003 q?8 ?/p>
适用于:(x)
Microsoft] ASP.NET
摘要Q了解ؓ(f) ASP.NET Web 面建立的事件模型,以及 Web 面转变?HTML q程中的各个阶段。ASP.NET HTTP q行时负责管理对象管道,q些对象首先请求的 URL 转换?Page cȝ具体实例Q然后再这些实例{换成U?HTML 文本。本文将探讨那些作ؓ(f)面生命周期标志的事Ӟ以及控g和页面编写者如何干预ƈ改变标准行ؓ(f)。(本文包含一些指向英文站点的链接。)
?/a>
真正?Page c?/a>
面的生命周?/a>
执行的各个阶D?/a>
结
对由 Microsoft] Internet 信息服务 (IIS) 处理?Microsoft] ASP.NET 面的每个请求都?x)被UM?ASP.NET HTTP 道。HTTP 道׃pd托管对象l成Q这些托对象按序处理hQƈ?URL 转换为纯 HTML 文本。HTTP 道的入口是 HttpRuntime cRASP.NET l构助进E中的每?AppDomain 创徏一个此cȝ实例。(h意,辅助q程为每个当前正在运行的 ASP.NET 应用E序l护一个特定的 AppDomain。)
HttpRuntime cM内部池中获取 HttpApplication 对象Qƈ安排此对象来处理h。HTTP 应用E序理器完成的主要d是扑ֈ真正处理请求的cR当h .aspx 资源Ӟ处理E序是面处理E序Q即?Page l承的类的实例。资源类型和处理E序cd之间的关联关pd储在应用E序的配|文件中。更切地说Q默认的映射集是?machine.config 文g?<httpHandlers> 部分定义的。但是,应用E序可以在本地的 web.config 文g中自定义自己?HTTP 处理E序列表。以下这一行代码就是用来ؓ(f) .aspx 资源定义 HTTP 处理E序的?/p>
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
扩展名可以与处理E序cȝ兌Qƈ且更多是与处理程序工厂类相关联。在所有情况下Q负责处理请求的 HttpApplication 对象都会(x)获得一个实?IHttpHandler 接口的对象。如果根?HTTP 处理E序来解析关联的资源/c,则返回的cd直接实现接口。如果资源被l定到处理程序工厂,则还需要额外的步骤。处理程序工厂类实现 IHttpHandlerFactory 接口Q此接口?GetHandler Ҏ(gu)返回一个基?IHttpHandler 的对象?/p>
HTTP q行时是如何l束q个循环q处理页面请求的Q?b>ProcessRequest Ҏ(gu)?IHttpHandler 接口中非帔R要。通过对代表被h面的对象调用此Ҏ(gu)QASP.NET l构?x)启动将生成览器输出的q程?/p>真正?Page c?/font>
特定面?HTTP 处理E序cd取决?URL。首ơ调?URL Ӟ构Z个新的类Q这个类被动态编译ؓ(f)一个程序集。检?.aspx
资源的分析进E的l果是类的源代码。该c被定义为命名空?ASP 的组成部分,q且被赋予了一个模拟原?URL 的名U。例如,如果 URL
的终Ҏ(gu) page.aspxQ则cȝ名称是 ASP.Page_aspx。不q,cȝ名称可以通过~程方式来控ӞҎ(gu)是在 @Page 指o(h)中设|?ClassName 属性?/p>
HTTP 处理E序的基cL Page。这个类定义了由所有页面处理程序共享的Ҏ(gu)和属性的最集合?b>Page cd?IHttpHandler 接口?/p>
在很多情况下Q实际处理程序的基类q不?PageQ而是其他的类。例如,如果使用了代码分,׃(x)出现q种情况。代码分L一开
发技术,它可以将面所需的代码隔d单独?C# ?Microsoft Visual Basic] .NET
cM。页面的代码是一l事件处理程序和辅助Ҏ(gu)Q这些处理程序和Ҏ(gu)真正军_了页面的行ؓ(f)。可以?<script runat=server> 标记Ҏ(gu)代码q行内联定义Q或者将其放|在外部c(代码分离c)中。代码分ȝ是从 Page l承q用额外的Ҏ(gu)的类Q被指定用作 HTTP 处理E序的基cR?/p>
q有一U情况,HTTP 处理E序也不是基?Page 的,卛_应用E序配置文g?<pages> 部分中,包含?PageBaseType 属性的重新定义?/p> PageBaseType 属性指明包含页面处理程序的基类的类型和E序集。从 Page 导出的这个类可以自动赋予处理E序扩展的自定义Ҏ(gu)和属性集?/p>面的生命周?/font>
完全识别 HTTP 面处理E序cdQASP.NET q行时将调用处理E序?ProcessRequest Ҏ(gu)来处理请求。通常情况下,无需更改此方法的实现Q因为它是由 Page cL供的?/p>
此实现将从调用ؓ(f)面构徏控g?wi)?FrameworkInitialize Ҏ(gu)开始?b>FrameworkInitialize Ҏ(gu)?TemplateControl c(Page 本n从此cd出)的一个受保护的虚拟成员。所有ؓ(f) .aspx 资源动态生成的处理E序都将覆盖 FrameworkInitialize。在此方法中Q构Z面的整个控件树(wi)?/p>
接下来,ProcessRequest 佉K面经历了各个阶段Q初始化、加载视囄态信息和回发数据、加载页面的用户代码以及执行回发服务器端事g。之后,面q入昄模式Q收集更新的视图状态,生成 HTML 代码q后将代码发送到输出控制台。最后,卸蝲面Qƈ认ؓ(f)h处理完毕?/p>
在各个阶D中Q页面会(x)触发数几个事gQ这些事件可以由 Web 控g和用户定义的代码截取q进行处理。其中的一些事件是嵌入式控件专用的Q因此无法在 .aspx 代码U进行处理?/p>
要处理特定事件的面应该明确注册一个适合的处理程序。不q,Z向后兼容早期?Visual Basic ~程风格QASP.NET
也支持隐式事件挂钩的形式。默认情况下Q页面会(x)试特定的Ҏ(gu)名称与事件相匚wQ如果实现匹配,则认为此Ҏ(gu)是匚w事g的处理程序。ASP.NET
提供了六U方法名U的特定识别Q它们是 Page_Init?b>Page_Load?b>Page_DataBind?b>Page_PreRender ?Page_Unload。这些方法被认ؓ(f)是由 Page cL供的相应事g的处理程序。HTTP q行时会(x)自动这些方法绑定到面事gQ这P开发h员就不必再编写所需的粘接代码了。例如,如果命名?Page_Load 的方法绑定到面?Load 事gQ则可省M下代码?/p> 对特定名U的自动识别是由 @Page 指o(h)?AutoEventWireup 属性控制的。如果该属性设|ؓ(f) falseQ则要处理事件的所有应用程序都需要明连接到面事g。不使用自动l定事g的页面性能?x)稍好一些,因ؓ(f)不需要额外匹配名UC事g。请注意Q所?Microsoft Visual Studio] .NET 目都是在禁?AutoEventWireup 属性的情况下创建的。但是,该属性的默认讄?trueQ即 Page_Load {方法会(x)被识别,q被l定到相兌的事件?/p>
下表中按序列出了页面的执行包括的几个阶D,执行的标志是一些应用程序的事件和/或受保护q可覆盖的方法?/p>
?1QASP.NET 面生命中的关键事g 以上所列的阶段中有些在面U是不可见的Qƈ且仅Ҏ(gu)务器控g的编写者和要创Z Page 导出的类的开发h员有意义?b>Init?b>Load?b>PreRender?b>UnloadQ再加上由嵌入式控g定义的所有回发事Ӟ构成了向外发送页面的各个阶段标记?/p>执行的各个阶D?/font>
面生命周期中的W一个阶D|初始化。这个阶D늚标志?Init 事g。在成功创徏面的控件树(wi)后,对应用E序触发此事件。换句话_(d)?Init 事g发生Ӟ.aspx 源文件中静态声明的所有控仉已实例化q用各自的默认倹{控件可以截?Init 事g以初始化在传入的 Web h的生命周期内所需的所有设|。例如,q时控g可以加蝲外部模板文g或设|事件的处理E序。请注意Q这时视囄态信息尚不可用?/p>
初始化之后,面框架加载页面的视图状态。视囄态是名称/值对的集合,在此集合中,控g和页面本w存储了Ҏ(gu)?Web
h都必dl有效的全部信息。视囄态代表了面的调用上下文。通常Q它包含上次在服务器上处理页面时控g的状态。首ơ在?x)话中请求页面时Q视囄态ؓ(f)
I。默认情况下Q视囄态存储在静默d到页面的隐藏字段中,该字D늚名称?__VIEWSTATE。通过覆盖 LoadViewState Ҏ(gu)Q?b>Control cȝ受保护、可覆盖Ҏ(gu)Q,lg开发h员可以控制视囄态的存储方式以及视图状态的内容映射到内部状态的方式?/p>
有些Ҏ(gu)Q如 LoadPageStateFromPersistenceMedium 以及其对应的 SavePageStateToPersistenceMediumQ,可以用来视囄态加载ƈ保存到其他存储介质(例如?x)话、数据库或服务器端文Ӟ中。与 LoadViewState 不同Q上q方法只能在?Page 导出的类中用?/p>
存储视图状态之后,面?wi)中控g的状态与面最后一ơ显C在览器中的状态相同。下一步是更新它们的状态以加入客户端的更改。处理回发数据阶D控g有机?x)更新其状态,从而准反映客L(fng)相应?HTML 元素的状态。例如,服务器的 TextBox 控g对应?HTML 元素?<input type=text>。在回发数据阶段QTextBox 控g检?<input> 标记的当前|q用该值来h自己内部的状态。每个控仉要从回发的数据中提取值ƈ更新自己的部分属性?b>TextBox 控g更新它?Text 属性,?CheckBox 控g刷新它?Checked 属性。服务器控g?HTML 元素的对应关pd以通过二者的 ID 扑ֈ?/p>
在处理回发数据阶D늚最后,面中的所有控件的状态都用客L(fng)输入的更Ҏ(gu)更新前一状态。这Ӟ对面触发 Load 事g?/p>
面中可能会(x)有一些控Ӟ当其某个敏感属性在两个不同的请求中被修Ҏ(gu)Q需要完成特定的d。例如,如果 TextBox 控g的文本在客户端被修改Q则此控件将触发 TextChanged 事g。每个控件在其一个或多个属性被修改为客L(fng)输入的值时都可以决定触发相应的事g。对于这些更改对光常关键的控gQ控件实?IPostBackDataHandler 接口Q此接口?LoadPostData Ҏ(gu)是在 Load 事g后立卌用的。通过?LoadPostData Ҏ(gu)q行~码Q控件将验证自上ơ请求后是否发生了关键更改,q触发自q更改事g?/p>
面生命周期中的关键事g是被调用以执行服务器端代码的事gQ此代码与客L(fng)触发的事件相兌。当用户单击按钮Ӟ回发页面。回发值的集合中包括启动整个操作的按钮?ID。如果控件实?IPostBackEventHandler 接口Q如按钮和链接按钮)Q页面框架将调用 RaisePostBackEvent Ҏ(gu)。此Ҏ(gu)的行为取决于控g的类型。就按钮和链接按钮而言Q此Ҏ(gu)查?Click 事g处理E序q运行相关的委托?/p>
处理完回发事件之后,面可以显CZ。这个阶D늚标志?PreRender 事g。控件可以利用这D|间来执行那些需要在保存视图状态和昄输出的前一L行的更新操作。下一个状态是 SaveViewStateQ在此状态中Q所有控件和面本n都将更新自己 ViewState 集合的内宏V然后,得到序列化、散列、Base64 ~码的视囄态,而且此视囄态与隐藏字段 __VIEWSTATE 相关联?/p>
通过覆盖 Render Ҏ(gu)可以改变各个控g的显C机制。此Ҏ(gu)接受 HTML 书写器对象,q用此对象来积累所有要为控件生成的 HTML 文本?b>Page cȝ Render Ҏ(gu)的默认实现包括对所有成员控件的递归调用。对于每个控Ӟ面都将调用 Render Ҏ(gu)Qƈ~存 HTML 输出?/p>
面生命中的最后一个标志是 Unload 事gQ在面对象消除之前发生。在此事件中Q?zhn)应该释放所有可能占用的关键资源Q例如文件、图形对象、数据库q接{)?/p>
在此事g之后Q也是最后,览器接?HTTP 响应数据包ƈ昄面?/p>结
ASP.NET 面对象模型因其事g机制而显得格外新颖独牏VWeb 面由控件组成,q些控g既可以生丰富的Z HTML
的用L(fng)面,又可以通过事g与用户交互。以前,?Web
应用E序的上下文中设|事件模型是件有挑战性的工作。可我们惊奇的看刎ͼ客户端生成的事g可以由服务器端的代码来解冻I而且只进行一些相应的修改后,此过
E仍可以输出相同?HTML 面?/p>
掌握q个模型对于了解面生命周期的各个阶D,以及面对象如何?HTTP q行时实例化q用是非常重要的?/p>
Dino Esposito 是一位来自意大利|马的培训教师和N。作?Wintellect 团队的成员,Dino 专门研究 ASP.NET ?ADO.NETQ主要在Ƨ洲和美国从事教学和咨询工作。此外,Dino q负责管?Wintellect ?ADO.NET 课gQƈ?MSDN 期刊的“Cutting Edge”专栏撰写文章。要与他联系Q请?dinoe@wintellect.com 发送电(sh)子邮件?/p>
发表?2003q?1??8:18
<pages PageBaseType="Classes.MyPage, mypage" />
this.Load += new EventHandler(this.Page_Load);
阶段
面事g
可覆盖的Ҏ(gu)
面初始?/td>
Init
加蝲视图状?/td>
LoadViewState
处理回发数据
L实现 IPostBackDataHandler 接口的控件中?LoadPostData Ҏ(gu)
加蝲面
Load
回发更改通知
L实现 IPostBackDataHandler 接口的控件中?RaisePostDataChangedEvent Ҏ(gu)
处理回发事g
由控件定义的L回发事g
L实现 IPostBackDataHandler 接口的控件中?RaisePostBackEvent Ҏ(gu)
面昄前阶D?/td>
PreRender
保存视图状?/td>
SaveViewState
昄面
Render
卸蝲面
Unload
关于作?/h3>