【Michael Xu】ASP.NET AJAX 客戶端生命週期事件

iDotNetSpace發表於2008-07-14

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
 2
 3BR> 4 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 5
 6
 7
 8
 9
10http://www.w3.org/1999/xhtml" >
11
12    Client Event Example
13   
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   
18
19
20   
21   


22       
23       
24          
25       

26       

27       
28       
29            Postbacks from inside the outer panel and inner panel are
30            asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
31
32           


33           
34            Last updated on
35           
36           


37
38           
39           
40               
41                Last updated on
42               
43               

44           

45           

46       

47       

48
49       
50
51       
52        test/'>http://www.microsoft.com">test/ Window Unload
53       

54           
55   

56   
57
58
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.
";
21}
22function ApplicationLoad(sender, args) {
23  $get('ClientEvents').innerHTML += "APP:: Application load. ";
24  $get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")
";
25}
26function ApplicationUnload(sender) {
27  alert('APP:: Application unload.');
28}
29function ApplicationDisposing(sender) {
30  $get('ClientEvents').innerHTML += "APP:: Application disposing.
";
31 
32}
33// Application event handlers for page developers.
34function pageLoad() {
35  $get('ClientEvents').innerHTML += "PAGE:: Load.
";
36}
37
38function pageUnload() {
39  alert('Page:: Page unload.');
40}
41
42// PageRequestManager event handlers.
43function InitializeRequest(sender, args) {
44  $get('ClientEvents').innerHTML += "


";
45  $get('ClientEvents').innerHTML += "PRM:: Initializing async request.
"; 
46}
47function BeginRequest(sender, args) {
48  $get('ClientEvents').innerHTML += "PRM:: Begin processing async request.
";
49}
50function PageLoading(sender, args) {
51  $get('ClientEvents').innerHTML += "PRM:: Loading results of async request.
";
52  var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
53  var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
54 
55  var message = "--&gt" + updatedPanels + "
--&gt" + deletedPanels + "
";
56 
57  document.getElementById("ClientEvents").innerHTML += message;
58}
59function PageLoaded(sender, args) {
60  $get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.
";
61  var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
62  var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
63   
64  var message = "--&gt" + updatedPanels + "
--&gt" + createdPanels + "
";
65       
66  document.getElementById("ClientEvents").innerHTML += message;
67}
68function EndRequest(sender, args) {
69  $get('ClientEvents').innerHTML += "PRM:: End of async request.
";
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 事件依然會被引發,但是新頁面不會被顯示出來。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-401189/,如需轉載,請註明出處,否則將追究法律責任。

相關文章