更新:2007 年 11 月
支持 AJAX 的 ASP.NET 页不仅引发与 ASP.NET 2.0 网页一样的服务器生命周期事件,还引发客户端生命周期事件。这些客户端事件可让您自定义回发和异步回发(部分页更新)的用户界面,还可帮助您在浏览器中页的生存期内,管理自定义脚本组件。
这些客户端事件由 Microsoft AJAX Library 中的类引发。当页包含 ASP.NET AJAX 服务器控件时,这些类将自动实例化。客户端类提供了一些 API,使您能够绑定到事件并提供这些事件的处理程序。由于 Microsoft AJAX Library 是独立于浏览器的,因此,为处理程序编写的代码在所有支持的浏览器中的工作方式相同。
初始请求(GET 请求)和同步回发的关键事件是 Application 实例的 load 事件。当 load 事件处理程序中的脚本运行时,所有脚本和组件都已加载并可用。当启用 UpdatePanel 控件的部分页呈现时,关键客户端事件是 PageRequestManager 类的事件。这些事件为您提供了处理许多常见情况的能力,其中包括取消回发的能力、赋予一个回发优于另一个回发的优先级的能力以及在刷新 UpdatePanel 控件的内容时对这些控件进行动画处理的能力。
无论您是在创建页还是在编写组件,客户端事件都很有用。如果您是一名网页开发人员,则可以提供一个在浏览器中加载和卸载页时将调用的自定义脚本。
有关服务器生命周期事件的更多信息,请参见 ASP.NET 页生命周期概述。
客户端类
在 ASP.NET AJAX 网页的客户端生命周期内,引发事件的两个主要的 Microsoft AJAX Library 类分别是 Application 和 PageRequestManager 类。
当页包含 ScriptManager 控件时,将在浏览器中实例化 Application 类。虽然 Application 类与 Page 服务器控件(派生自 Control 类)类似,但它提供了用于引发服务器事件的附加功能。同样,Application 类派生自 Sys.Component 类,但它会引发您可处理的客户端生命周期事件。
如果页包含一个 ScriptManager 控件和一个或多个 UpdatePanel 控件,则该页可执行部分页更新(如果浏览器支持并已启用部分页呈现)。在此情况下,浏览器中将自动获得 PageRequestManager 类的实例。PageRequestManager 类将引发特定于异步回发的客户端事件。有关部分页呈现的详细信息,请参见部分页呈现概述。
添加客户端事件的处理程序
若要添加或移除由 Application 和 PageRequestManager 类引发的事件的处理程序,请使用这些类的 add_事件名 和 remove_事件名 方法。下面的示例演示如何将名为 MyLoad 的处理程序添加到 Application 对象的 init 事件。
Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);
Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);
![]() |
---|
本示例仅演示 add_事件名 和 remove_事件名 方法的语法。本主题的后面部分提供了有关使用特定事件可进行的操作的详细信息。 |
处理应用程序加载和卸载事件
若要处理 Application 对象的 load 和 unload 事件,不必将处理程序显式绑定到事件,可以改为创建使用保留名称 pageLoad 和 pageUnload 的函数。下面的示例演示如何使用此方法为 Application 对象的 load 事件添加处理程序。
function pageLoad(sender, args) {
}
function pageLoad(sender, args) {
}
其他客户端类的事件
本主题仅描述由 Application 和 PageRequestManager 类引发的事件。Microsoft AJAX Library 还包含用于为 DOM 元素事件添加、清除和移除处理程序的类。这些类包括:
Sys.UI.DomEvent.addHandler 方法或快捷方式 $addHandler。
本主题中不讨论由 DOM 元素引发的事件。
Application 和 PageRequestManager 类的客户端事件
下面列出了 Application 和 PageRequestManager 类的客户端事件,可以在支持 AJAX ASP.NET 的页中处理这些事件。本主题的后面部分将描述引发事件的顺序。
事件 |
说明 |
---|---|
在已加载所有脚本之后并在创建任何对象之前引发。如果正在编写一个组件,则 init 事件为您在页生命周期中将您的组件添加到页中提供了一个机会。这样,其他组件或脚本以后就可以在页生命周期中使用所添加的组件了。如果您是一名网页开发人员,则在大多数情况下,应使用 load 事件而不是 init 事件。 当首次呈现页时,仅引发一次 init 事件。后续的部分页更新不会引发 init 事件。 |
|
在已加载所有脚本且应用程序中使用 $create 创建的所有对象已初始化之后引发。对于所有针对服务器的回发(包括异步回发)引发 load 事件。 如果您是一名网页开发人员,则可以创建一个名为 pageLoad 的函数以自动提供 load 事件的处理程序。在已由 add_load 方法添加到 load 事件的任何处理程序之后,调用 pageLoad 处理程序。 load 事件将采用 eventargs 参数,该参数是一个 Sys.ApplicationLoadEventArgs 对象。可以使用事件参数来确定是否因部分页更新而刷新页以及自引发上一个 load 事件之后创建了哪些组件。 |
|
在释放所有对象之前和浏览器窗口的 window.unload 事件发生之前引发。 如果您是一名网页开发人员,则可以创建一个名为 pageUnload 的函数以自动提供 unload 事件的处理程序。pageUnload 事件刚好在从浏览器中卸载页之前进行调用。在此事件过程中,应释放代码所占有的任何资源。 |
|
在组件的属性发生更改时可能引发。仅当组件开发人员在属性 Set 访问器中调用 Sys.Component.raisePropertyChange 方法时引发此事件。有关更多信息,请参见定义自定义组件属性和引发 PropertyChanged 事件。 propertyChanged 事件将采用 eventargs 参数,该参数是一个 Sys.applicationLoadEventArgs 对象。 |
|
释放 Application 实例时引发。 |
|
在异步请求开始之前引发。可以使用此事件来取消回发,如为另一个异步回发赋予优先权。 initializeRequest 事件将采用 eventargs 参数,该参数是一个 Sys.WebForms.InitializeRequestEventArgs 对象。此对象可提供导致回发的元素和基础请求对象。InitializeRequestEventArgs 还公开 cancel 属性。如果将 cancel 设置为 true,则会取消新的回发。 |
|
在启动一个异步回发并将其发送到服务器之前引发。如果有一个回发已在处理,则将停止该回发(通过使用 abortPostBack 方法)。可以使用此事件来设置请求标头,或开始页上的动画以指示正在对请求进行处理。 beginRequest 事件将采用 eventargs 参数,该参数是一个 Sys.WebForms.BeginRequestEventArgs 对象。此对象可提供导致回发的元素和基础请求对象。 |
|
在从服务器收到对异步回发的响应之后但在页上的任何内容更新之前引发。可以使用此事件为更新的内容提供自定义转换效果。 pageLoading 事件将采用 eventargs 参数,该参数是一个 Sys.WebForms.PageLoadingEventArgs 对象。此对象可提供一些与因最新的异步回发而要删除和更新的面板有关的信息。 |
|
在因同步回发或异步回发而刷新页上的所有内容之后引发。对于同步回发,仅可以创建面板;而对于异步回发,则可以创建和更新面板。可以使用此事件管理针对更新内容的自定义转换效果。 pageLoaded 事件将采用 eventargs 参数,该参数是一个 Sys.WebForms.PageLoadedEventArgs 对象。此对象可提供一些与在最新的回发中更新和创建的面板有关的信息。 |
|
在处理异步回发的响应并更新页之后或在响应的处理过程中(如果存在错误)引发。如果出错,则不更新页。使用此事件可为用户提供自定义的错误通知或记录错误。 endRequest 事件将采用 eventargs 参数,该参数是一个 Sys.WebForms.EndRequestEventArgs 对象。此对象可提供一些与发生的错误以及是否已处理错误有关的信息,还可提供响应对象。 |
事件顺序示例
下面的示例演示在包含两个 UpdatePanel 控件(一个控件嵌套在另一个控件中)的页上引发的客户端事件。您将发现单击父面板中的按钮与单击嵌套的面板中的按钮之间的区别。父面板中的按钮会导致更新父面板,并导致删除和重新创建嵌套的面板。嵌套的面板中的按钮仅会导致更新嵌套的面板。
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Client Event Example</title>
<style type="text/css">
#OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
#NestedPanel { width: 596px; height: 60px; border: 2px solid green;
margin-left:5 px; margin-right:5px; margin-bottom:5px;}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="ClientEventTest.js" />
</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" runat="server">
<ContentTemplate>
Postbacks from inside the outer panel and inner panel are
asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
<br /><br />
<asp:Button ID="OPButton1" Text="Outer Panel Button" runat="server" />
Last updated on
<%= DateTime.Now.ToString() %>
<br /><br />
<asp:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Button ID="NPButton1" Text="Nested Panel 1 Button" runat="server" />
Last updated on
<%= DateTime.Now.ToString() %>
<br />
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:UpdatePanel>
<input type="button" onclick="Clear();" value="Clear" />
<asp:Button ID="FullPostBack" runat="server" Text="Full Postback" />
<a href="https://www.microsoft.com">Test Window Unload</a>
<br />
<span id="ClientEvents"></span>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Client Event Example</title>
<style type="text/css">
#OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
#NestedPanel { width: 596px; height: 60px; border: 2px solid green;
margin-left:5 px; margin-right:5px; margin-bottom:5px;}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="ClientEventTest.js" />
</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" runat="server">
<ContentTemplate>
Postbacks from inside the outer panel and inner panel are
asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
<br /><br />
<asp:Button ID="OPButton1" Text="Outer Panel Button" runat="server" />
Last updated on
<%= DateTime.Now.ToString() %>
<br /><br />
<asp:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Button ID="NPButton1" Text="Nested Panel 1 Button" runat="server" />
Last updated on
<%= DateTime.Now.ToString() %>
<br />
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:UpdatePanel>
<input type="button" onclick="Clear();" value="Clear" />
<asp:Button ID="FullPostBack" runat="server" Text="Full Postback" />
<a href="https://www.microsoft.com">Test Window Unload</a>
<br />
<span id="ClientEvents"></span>
</div>
</form>
</body>
</html>
// Hook up Application event handlers.
var app = Sys.Application;
app.add_load(ApplicationLoad);
app.add_init(ApplicationInit);
app.add_disposing(ApplicationDisposing);
app.add_unload(ApplicationUnload);
// Application event handlers for component developers.
function ApplicationInit(sender) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack())
{
prm.add_initializeRequest(InitializeRequest);
prm.add_beginRequest(BeginRequest);
prm.add_pageLoading(PageLoading);
prm.add_pageLoaded(PageLoaded);
prm.add_endRequest(EndRequest);
}
$get('ClientEvents').innerHTML += "APP:: Application init. <br/>";
}
function ApplicationLoad(sender, args) {
$get('ClientEvents').innerHTML += "APP:: Application load. ";
$get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
}
function ApplicationUnload(sender) {
alert('APP:: Application unload.');
}
function ApplicationDisposing(sender) {
$get('ClientEvents').innerHTML += "APP:: Application disposing. <br/>";
}
// Application event handlers for page developers.
function pageLoad() {
$get('ClientEvents').innerHTML += "PAGE:: Load.<br/>";
}
function pageUnload() {
alert('Page:: Page unload.');
}
// PageRequestManager event handlers.
function InitializeRequest(sender, args) {
$get('ClientEvents').innerHTML += "<hr/>";
$get('ClientEvents').innerHTML += "PRM:: Initializing async request.<br/>";
}
function BeginRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Begin processing async request.<br/>";
}
function PageLoading(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function PageLoaded(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function EndRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: End of async request.<br/>";
}
// Helper functions.
function Clear()
{
$get('ClientEvents').innerHTML = "";
}
function printArray(name, arr)
{
var panels = name + '=' + arr.length;
if(arr.length > 0)
{
panels += "(";
for(var i = 0; i < arr.length; i++)
{
panels += arr[i].id + ',';
}
panels = panels.substring(0, panels.length - 1);
panels += ")";
}
return panels;
}
// Hook up Application event handlers.
var app = Sys.Application;
app.add_load(ApplicationLoad);
app.add_init(ApplicationInit);
app.add_disposing(ApplicationDisposing);
app.add_unload(ApplicationUnload);
// Application event handlers for component developers.
function ApplicationInit(sender) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack())
{
prm.add_initializeRequest(InitializeRequest);
prm.add_beginRequest(BeginRequest);
prm.add_pageLoading(PageLoading);
prm.add_pageLoaded(PageLoaded);
prm.add_endRequest(EndRequest);
}
$get('ClientEvents').innerHTML += "APP:: Application init. <br/>";
}
function ApplicationLoad(sender, args) {
$get('ClientEvents').innerHTML += "APP:: Application load. ";
$get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
}
function ApplicationUnload(sender) {
alert('APP:: Application unload.');
}
function ApplicationDisposing(sender) {
$get('ClientEvents').innerHTML += "APP:: Application disposing. <br/>";
}
// Application event handlers for page developers.
function pageLoad() {
$get('ClientEvents').innerHTML += "PAGE:: Load.<br/>";
}
function pageUnload() {
alert('Page:: Page unload.');
}
// PageRequestManager event handlers.
function InitializeRequest(sender, args) {
$get('ClientEvents').innerHTML += "<hr/>";
$get('ClientEvents').innerHTML += "PRM:: Initializing async request.<br/>";
}
function BeginRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Begin processing async request.<br/>";
}
function PageLoading(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function PageLoaded(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function EndRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: End of async request.<br/>";
}
// Helper functions.
function Clear()
{
$get('ClientEvents').innerHTML = "";
}
function printArray(name, arr)
{
var panels = name + '=' + arr.length;
if(arr.length > 0)
{
panels += "(";
for(var i = 0; i < arr.length; i++)
{
panels += arr[i].id + ',';
}
panels = panels.substring(0, panels.length - 1);
panels += ")";
}
return panels;
}
常见情况的事件顺序
事件的顺序与页上使用的控件以及发出请求的类型(初始请求、回发或异步回发)有关。本节描述几种常见情况的事件的顺序。
初始请求
在页的初始请求过程中,将引发有限数量的客户端事件。假定初始请求的以下情况:
页包含 ScriptManager 控件,且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性均为 true。
该请求为 GET 请求。
成功返回来自服务器的响应。
以下客户端事件按此顺序发生:
将初始请求发送到服务器。
客户端接收响应。
Application 实例引发 init 事件。
Application 实例引发 load 事件。
在浏览器中的页的生存期内,Application 实例的 init 事件仅引发一次。对于后续异步回发,不再引发此事件。在初始请求期间,不引发任何 PageRequestManager 事件。
异步回发
异步回发可将一些页数据发送到服务器、接收响应并更新页的一部分。假定异步回发的以下情况:
页包含 ScriptManager 控件,且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性均为 true。
页包含 UpdatePanel 控件,且该控件的 ChildrenAsTriggers 属性为 true。
UpdatePanel 控件内的按钮启动异步回发。
成功返回来自服务器的响应。
以下客户端事件按此顺序发生:
单击 UpdatePanel 内的按钮,这将启动异步回发。
PageRequestManager 实例引发 initializeRequest 事件。
PageRequestManager 实例引发 beginRequest 事件。
将请求发送到服务器。
客户端接收响应。
PageRequestManager 实例引发 pageLoading 事件。
PageRequestManager 实例引发 pageLoaded 事件。
Application 实例引发 load 事件。
PageRequestManager 实例引发 endRequest 事件。
有关更多信息,请参见处理 PageRequestManager 事件。
请注意,Application 实例的 load 事件将在 PageRequestManagerpageLoaded 事件之后而在其 endRequest 事件之前引发。
多个异步回发
当在服务器上或浏览器中完成对上一个已启动的请求的处理之前,如果用户启动新的请求,则会引发多个异步回发。假定多个异步回发的以下情况:
页包含 ScriptManager 控件,且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性均为 true。
页包含 UpdatePanel 控件。
单击 UpdatePanel 控件内用于启动异步回发的按钮两次。当服务器正在处理由第一次单击启动的请求时,发生第二次单击。
从服务器成功返回对第一个请求的响应。
以下客户端事件按此顺序发生:
单击 UpdatePanel 内的按钮,这将启动异步回发。
PageRequestManager 实例引发 initializeRequest 事件。
PageRequestManager 实例引发 beginRequest 事件。
将请求发送到服务器。
再次单击该按钮,这将启动第二次异步回发。
PageRequestManager 实例为第二次按钮单击引发 initializeRequest 事件。
PageRequestManager 实例为第一次按钮单击引发 endRequest 事件。
PageRequestManager 实例为第二次按钮单击引发 beginRequest 事件。
将第二次单击启动的请求发送到服务器。
为第二次单击接收响应。
PageRequestManager 实例引发 pageLoading 事件。
PageRequestManager 实例引发 pageLoaded 事件。
Application 实例引发 load 事件。
PageRequestManager 实例引发 endRequest 事件。
异步回发的默认行为是最新的异步回发优先。如果有两个异步回发接连发生,且第一个回发仍在浏览器中进行处理,则取消第一个回发。如果已向服务器发送第一个回发,则当该回发到达服务器时,服务器将处理第二个请求,而不会返回第一个请求。有关如何对特定异步回发赋予优先级的信息,请参见为特定异步回发赋予优先级。
离开页
当用户离开某个页时,将从浏览器中卸载当前页,您可以处理 unload 事件以释放资源。假定离开页的以下情况:
页包含 ScriptManager 控件,且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性均为 true。
目标页存在。
以下客户端事件按此顺序引发:
启动对新页的请求。
浏览器接收对新页的响应。
Application 实例引发 unload 事件。
将显示新页。
如果新页的请求中存在错误,则仍将引发 unload 事件,但不显示新页。