ASP.NET AJAX 客户端生命周期事件

本文翻译:Valens
英语原文:http://ajax.asp.net/docs/overview/AJAXClientEvents.aspx
欢迎大家提出意见,我会积极进行修改的!

Introduction【介绍】  

微软Ajax提出了与ASP.NET 2.0页面服务器端生命周期事件相似的客户端生命周期事件。这些客户端事件使得我们能为传统回送和异步回送(部分页面刷新)都能定制自己的用户界面。它们还可以在整个页面生命周期期间帮助你管理和使用自定义的脚本。

这些客户端事件在微软的AJAX Libray的类中都被提出来了(我们可以在AJAX Libray的类中找到它们)。当加载一个带有AJAX服务器控件时,这些类都会自动地实例化(instantiated?)。这些类提供了一些APIs以便我们能够将事件绑定到事件提供处理程序。并且AJAX Library是独立于浏览器的,所以你写的代码可以工作在所有支持的浏览器。

关键的事件是初始化请求和异步回送的应用程序实例的 load 事件。当脚本在加载处理事件运行时,所有的脚本和组件都已经被加载并且是可用的。当使用了 UpdatePanel 控件部分页面刷新时,所有客户端事件中最关键的就是 PageRequestManager 类。这些客户端事件使得你能够实现某些场景。比如包括了: 撤销回送,为一个回送设置更高的优先级,还可以使 UpdatePanel 在刷新的时候交互得更好。

这些事件对于我们创建页面或写组件都有很大的帮助。如果你是一个网页开发人员,你可以为页面在加载和卸载时使用定制的脚本。

向了解更多服务器端生命周期事件,可以参考 ASP.NET Page Life Cycle Overview.

Client Classes【客户端类】

在微软AJAX类库中提出了在AJAX网页的客户端生命周期中两个很主要的类: Application 类和 PageRequestManager 类。

当浏览器请求一个有包含有 ScriptManager 控件的页面时,Application 类就实例化了。Application 类和服务器端的 Page 控件类似,也是继承自 Control 类,不过却额外附加了一些功能(相比服务端事件)。类似的, Application 继承了 Sys.COmponent 类,除此,还提供了很多在客户端生命周期期间内的可操作事件。

如果一个页面包含了一个 ScriptManager,并且还存在了一个或更多的 UpdatePanel 控件,那么这个页面就可以实现部分更新的效果了。如果是那样的话,一个 PageRequestManager 类的实例对浏览器是可用的了。PageRequestManager 提供的客户端事件都是关于异步回送的。更多关于生成部分页面的细节请参考:Partial-Page Rendering Overview.

Adding Handlers for Client Events【为客户端事件增加Handler】

现在通过使用 Application 和 PageRequestManager 类中的 add_eventname 和 reomve_eventname 方法来添加或移除事件。下面这个例子展示了如何添加一个操作(handler)名为 MyLoad 到 Application 对象的 init 事件。

Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);

注释;这个例子只是展示了使用 add_eventname 和 remove_eventname 方法的语法。更多关于使用这个事件的细节将在后面的主题提供。

Handling the Application Load and Unload Events【操作Application的加载和卸载事件】

要操作 Application 对象的 load 和 unload 事件,不需要显示地绑定到一个操作事件。相反地,你可以直接使用保留关键字 pageLoad 和 pageUnload 来创建一个函数。下面这个例子展示了如何为 Application 的 load 事件添加一个操作。

function pageLoad(sender, args) {
}


Events for Other Client Classes【其它客户端类】

这个主题仅仅描述由 Application 和 PageRequestManager 类提供的事件。微软的AJAX类库还包括了以下的类用于 DOM 元素事件的添加、清除和移除。这些类包括了:

有 Sys.UI.DomEvent.addHandler 方法或简短写法 $addHandler.

有 Sys.UI.DomEvent.clearHandlers 方法或简短写法 $clearHandlers.

有 Sys.UI.DomEvent.removeHandler 方法或简短写法 $removeHandler.

有关 DOM 原理提供的事件不是本主题讨论的。

Client Events of the Application and PageRequestManager Classes【Application和PageRequestManager类的客户端事件】

下面的表格列出了你可以在 AJAX 的 ASP.NET 页面使用的 Application 和 PageRequestManager 类的客户端事件。事件发生的顺序将在稍后的主题中进行讨论。

Event
(事件名称)
 Description
(描述)
 
init Event
[初始化事件]
 在所有脚本被加载后,在任何一个对象被创建之前引发该事件。如果你打算写一个组件(脚本),init 事件提供了一个在生命周期内添加组件(脚本)到页面的点。该组件可以被其它在生命周期内的脚本调用。如果你是一个网页开发人员,在大多数的情况之下,建议用 load 事件来替代 init 事件来处理。

init 事件只在页面开始生成时创建一次。后来的部分页面刷新将不会引发 init 事件。
 
load Event
[加载事件]
 该事件在所有脚本被加载后,并且由使用 $create 初始化的所有程序对象被创建后引发。该事件将被所有回送到服务器引发,这些回送也包括异步的回送。

如果你是网页开发人员,你可以创建一个名为 pageLoad 的函数,该函数是由加载事件本身提供的。该 pageLoad 操作(handler)是在任何一个通过 add_load 方法被添加到 load 事件的操作后可以调用。

load 事件需要一个 Sys.ApplicationLoadEventArgs 对象作为 eventargs 参数。你可以通过该参数来决定页面是否需要显示部分刷新,还可以决定哪些组件应当在上一个引发 load 事件后被创建。
 
unload Event
[卸载事件]
 在所有对象被释放之前,在浏览器的 window.unload 事件发生之前被引发。

你可以通过系统自身提供的一个名为 pageUnload 的函数来处理卸载事件。pageUnload 事件是在页面在浏览器中卸载时调用。在该事件发生期间,我们应当释放由代码占用的全部资源。
 
propertyChanged Event
[属性改变事件]
 当某组件的属性发生改变时引发。应用程序对象是从 Component 类那里继承了这个事件。该事件仅在开发人员在设置一个属性值的时候调用了 Sys.Component.raisePropertyChange 方法而引发的。

更多信息请查看 Defining Custom Component Properties and Raising PropertyChanged Events.
属性改变事件需要一个 Sys.applicationLoadEventArgs 对象作为 eventargs 参数。
 
disposing Event
[释放事件]
 该事件是在应用程序实例被释放时引发的。应用程序对象从 Component 类继承了该事件。
 
initializeRequest Event
[初始化请求事件]
 该事件发生在一个异步请求开始时。你可以通过使用该事件来取消一个传统的回送,例如让一个异步回送获得优先。

初始化请求事件需要一个 Sys.WebForms.InitializeRequestEventArgs 对象提供的 eventargs 参数。该对象提供了那些引起回送和暗藏的(underlying)请求的对象的有用的元素。该事件还暴露了 cancel 属性。如果你设置 cancel 值为 true,一个新的回送将被撤销。
 
beginRequest Event
[开始请求事件]
 该事件是在一个回送到服务器的异步回送开始前引发。如果当前已经存在了一个回送进程,则会被停止(by using the abortPostBack method)。你可以使用该事件来设置请求的头部或显示一个有趣的(animation)提示在页面中,表示该请求正在进行中。

该事件需要一个 Sys.WebForms.BeginRequestEventArgs 对象作为 eventargs 参数。该对象提供了引起回送的和暗藏的(underlying)请求对象的有用的元素。
 
pageLoading Event
[页面正在加载事件]
 当确定一个异步回送被服务器端接收后,在页面任何内容被更新前引发。可以使用该事件来为需要更新的内容提供一个定制过渡效果。

该事件需要一个 Sys.WebForms.PageLoadingEventArgs 对象作为 eventargs 参数。该对象提供了最近的异步回送返回的结果关于哪些 panels 会被删除和更新的有用的信息。
 
pageLoaded Event
[页面加载完成事件]
 在页面所有内容被一个同步或异步回送结果刷新之后引发。在同步回送时,panels 只能被创建,但在异步回送时,panels 可以被创建和更新。可以通过使用该事件来管理一个为需要更新的内容定制的变化效果。

该事件需要一个 Sys.WebForms.PageLoadedEventArgs  对象作为 eventargs 参数。该对象提供了关于最近回送时的那些 panels 被更新和创建的有用的信息。
 
endRequest Event
[结束请求事件]
 在响应了完成一个异步回送和页面被更新后,或在请求过程中发生了错误后引发。如果发生了某个错误,页面将不会被更新。通过使用这个事件来提供一个定制的错误提示给访问者或登记到错误日志。

该事件需要一个 Sys.WebForms.EndRequestEventArgs 对象作为 eventargs 参数。该对象提供了有关被引发的错误和错误是否被处理的一些有用的信息。它还提供了有关相应对象的可用的信息。
 


Event Order Example 【事件顺序的例子】

下面的这个例子展示了在一个存在有两个嵌套的 UpdatePanel 控件的页面的客户端事件将被如何引发。请注意点击父 panel 中的按钮的和内嵌的 panel 中按钮的区别。在父 panel 中的按钮将引起父 panel 的更新,和嵌在其中的 panel 将被删除并重新创建。内嵌 panel 的按钮仅引起内嵌 panel 的更新。

页面代码:

 

 1<%@ Page Language="C#" %>
 2
 3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 4 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 5
 6<script runat="server">
 7
 8</script>
 9
10<html xmlns="http://www.w3.org/1999/xhtml" >
11<head runat="server">
12    <title>Client Event Example</title>
13    <style type="text/css">
14    #OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
15    #NestedPanel { width: 596px; height: 60px; border: 2px solid green;
16                   margin-left:5 px; margin-right:5px; margin-bottom:5px;}
17    </style>
18</head>
19<body>
20    <form id="form1" runat="server">
21    <div>
22        <asp:ScriptManager ID="ScriptManager1" runat="server">
23        <Scripts>
24           <asp:ScriptReference Path="ClientEventTest.js" />
25        </Scripts>
26        </asp:ScriptManager>
27        <asp:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" runat="server">
28        <ContentTemplate>
29            Postbacks from inside the outer panel and inner panel are
30            asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
31
32            <br /><br />
33            <asp:Button ID="OPButton1" Text="Outer Panel Button" runat="server" />
34            Last updated on
35            <%= DateTime.Now.ToString() %>
36            <br /><br />
37
38            <asp:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" runat="server">
39            <ContentTemplate>
40                <asp:Button ID="NPButton1" Text="Nested Panel 1 Button" runat="server" />
41                Last updated on
42                <%= DateTime.Now.ToString() %>
43                <br />
44            </ContentTemplate>
45            </asp:UpdatePanel>
46        </ContentTemplate>
47        </asp:UpdatePanel>
48
49        <input type="button" onclick="Clear();" value="Clear" />
50
51        <asp:Button ID="FullPostBack" runat="server" Text="Full Postback" />
52        <a href="http://www.microsoft.com">test/ Window Unload</a>
53        <br />
54        <span id="ClientEvents"></span>   
55    </div>
56    </form>
57</body>
58</html>
59

脚本代码:

 

 1// Hook up Application event handlers.
 2var app = Sys.Application;
 3app.add_load(ApplicationLoad);
 4app.add_init(ApplicationInit);
 5app.add_disposing(ApplicationDisposing);
 6app.add_unload(ApplicationUnload);
 7
 8
 9// Application event handlers for component developers.
10function ApplicationInit(sender) {
11  var prm = Sys.WebForms.PageRequestManager.getInstance();
12  if (!prm.get_isInAsyncPostBack())
13  {
14      prm.add_initializeRequest(InitializeRequest);
15      prm.add_beginRequest(BeginRequest);
16      prm.add_pageLoading(PageLoading);
17      prm.add_pageLoaded(PageLoaded);
18      prm.add_endRequest(EndRequest);
19  }
20  $get('ClientEvents').innerHTML += "APP:: Application init. <br/>";
21}
22function ApplicationLoad(sender, args) {
23  $get('ClientEvents').innerHTML += "APP:: Application load. ";
24  $get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
25}
26function ApplicationUnload(sender) {
27  alert('APP:: Application unload.');
28}
29function ApplicationDisposing(sender) {
30  $get('ClientEvents').innerHTML += "APP:: Application disposing. <br/>";
31 
32}
33// Application event handlers for page developers.
34function pageLoad() {
35  $get('ClientEvents').innerHTML += "PAGE:: Load.<br/>";
36}
37
38function pageUnload() {
39  alert('Page:: Page unload.');
40}
41
42// PageRequestManager event handlers.
43function InitializeRequest(sender, args) {
44  $get('ClientEvents').innerHTML += "<hr/>";
45  $get('ClientEvents').innerHTML += "PRM:: Initializing async request.<br/>"; 
46}
47function BeginRequest(sender, args) {
48  $get('ClientEvents').innerHTML += "PRM:: Begin processing async request.<br/>";
49}
50function PageLoading(sender, args) {
51  $get('ClientEvents').innerHTML += "PRM:: Loading results of async request.<br/>";
52  var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
53  var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
54 
55  var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
56 
57  document.getElementById("ClientEvents").innerHTML += message;
58}
59function PageLoaded(sender, args) {
60  $get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.<br/>";
61  var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
62  var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
63   
64  var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
65       
66  document.getElementById("ClientEvents").innerHTML += message;
67}
68function EndRequest(sender, args) {
69  $get('ClientEvents').innerHTML += "PRM:: End of async request.<br/>";
70}
71
72// Helper functions.
73function Clear()
74{
75  $get('ClientEvents').innerHTML = "";
76}
77function printArray(name, arr)
78{
79    var panels = name + '=' + arr.length;
80    if(arr.length > 0)
81    {
82        panels += "(";
83        for(var i = 0; i < arr.length; i++)
84        {
85            panels += arr[i].id + ',';
86        }
87        panels = panels.substring(0, panels.length - 1);
88        panels += ")";
89    }
90    return panels;
91}
92

运行效果   查看代码

Event Order for Common Scenarios【一般事件发生顺序】

事件触发顺序还是要看在页面中使用了什么控件和发生了什么类型的请求(初始化请求,传统回送或是异步回送)。这部分将描述几种常见情景的事件请求顺序。

Initial Request 【初始化请求】

在一个页面初始化请求过程中,少量的客户端事件被引发。假设下面就是初始化请求的情景。

    ·  页面包括一个 ScriptManager 控件,并且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性都为 true。
    ·  请求是 GET 类型;
    ·  服务器能正常响应。

下面是客户端事件发生的顺序:
1、初始化请求发生给服务器。
2、客户端接收到响应。
3、Application 实例引发 init 事件。
4、Application 实例引发 load 事件。

初始化事件仅在整个页面生命周期过程中的应用程序实例化时发生一次。它不会被后来的异步回送所引发。在初始化请求(注意是请求)期间,没有任何的 PageRequestManager 事件被引发。

Asynchronous Postback 【异步回送】

一个异步回送发送了一些页面数据到服务器,并接收一个服务器端的响应,然后刷新页面的一部分。假定下面一个异步回送的场景:

     ·  页面包括一个 ScriptManager 控件,并且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性都为 true。
     ·  页面存在一个 UpdatePanel 控件,并且改控件的 ChildrenAsTriggers 属性值为 true。
     ·  在 UpdatePanel 里面有一个按钮用于引发异步回送。
     ·  成功地从服务器端获得响应。

下面是客户端事件发生的顺序:
1、点击 UpdatePanel 控件中的按钮时,引起了一个异步回送。
2、PageRequestManager 实例引发了 initializeRequest 事件。
3、PageRequestManager 实例引发了 beginRequest 事件。
4、请求被发送到服务器。
5、客户端接收到了响应。
6、PageRequestManager 实例引发了 pageLoading 事件。
7、PageRequestManager 实例引发了 pageLoaded 事件。
8、Application 实例引发了 load 事件。
9、PageRequestManager 实例引发了 endRequest 事件。

请注意应用程序的 load 事件在 PageRequestManager 的 pageLoaded 事件之后,和 endRequest 事件之前。

Multiple Asynchronous Postbacks 【多个异步回送】

当之前的一个请求正在服务器端或浏览器中运行时,用户又发送了一个新的请求时,则发生了多个异步回送。假设下面的场景描述了多个异步回送的情况。

    ·   页面包括一个 ScriptManager 控件,并且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性都为 true。
     ·  页面包含一个 UpdatePanel 控件。
     ·  在 UpdatePanel 中有一个引发异步回送的按钮控件被点击两次。第二次的点击发生在服务器端正在处理第一次点击发起的请求。
     ·  获得了从服务器端返回的对第一次请求的响应。

下面是客户端事件发生的顺序:
1、点击 UpdatePanel 中的按钮引发了一次异步回送。
2、PageRequestManager 实例引发了 initializeRequest 事件。
3、PageRequestManager 实例引发了 beginRequest 事件。
4、请求被发送到服务器。
5、客户端接收到了响应。
6、按钮被再次点击,引发了第二次异步回送。
7、PageRequestManager 实例为第二次点击引发了 initializeRequest 事件。
8、PageRequestManager 实例为第二次点击引发了 beginRequest 事件。
9、第二次点击的请求北伐扫到了服务器。
10、客户端接收到了第二次点击的响应。
11、PageRequestManager 实例引发了 pageLoading 事件。
12、PageRequestManager 实例引发了 pageLoaded 事件。
13、Application 实例引发了 load 事件。
14、PageRequestManager 实例引发了 endRequest 事件。

默认的异步回送行为是最近发生的异步回送优先级较高。如果两个异步回送按顺序发生,并且第一个异步回送仍在浏览器处理中,则第一个回送被取消了。如果第一个回送已被发送到了服务器端,则服务器在第二个请求到来之前是不会返回第一个请求的。更多关于如何为异步回送设置优先级的详情请参考 Giving Precedence to a Specific Asynchronous Postback.

Browsing Away from a Page 【浏览其它页】

当用户从一个页面访问其它页面时,当前的页面会从浏览器中卸载,因此你可以操作 unload 事件来释放资源。假定下面模拟了这一场景。

     ·  页面包括一个 ScriptManager 控件,并且该控件的 SupportsPartialRendering 和 EnablePartialRendering 属性都为 true。
     ·  目标页面存在。

下面是客户端事件发生的顺序:
1、发动一个请求新页面的请求。
2、浏览器获得请求新页面的响应。
3、Application 实例引发 unload 事件。
4、显示了新页面。

如果在请求新页面时发生了错误,unload 事件依然会被引发,但是新页面不会被显示出来。

【完】

posted @ 2008-07-14 09:55  xumingming  阅读(558)  评论(0编辑  收藏  举报