asp.net頁面生存週期之頁面的建立

每次客戶端請求都會創建頁面實例,它的執行使自身及其包含的控件經歷頁面生命週期的各個階段。頁面的執行起始於http運行庫調用ProcessRequest時,該方法將啓動頁面並控制它的生命週期。生命週期由一系列階段和步驟組成。一些階段可以通過用戶編碼的時間進行控制,而一些需要對方法進行重寫。其他階段(更確切的說是子階段)沒有被公開,因而開發者無法控制。

頁面的生命週期可以分爲三個階段:建立階段、回發階段和終結階段。每個階段會有子階段,分別由若干步驟和事件引發點組成。這裏描述的生命週期包括所有可能的路徑。注意,具體情況會返回過程(跨頁投遞、腳本回調和回發)的不同而略有不同。

頁面的建立

當http運行庫實例化一個頁面類對當前請求進行處理時,頁面的構造函數會生成一個控件樹。該控件樹會關聯至實際的類,這些類的請求過程開始時,所有子控件和頁面的內部對象(如http上下文對象,請求對象和響應對象等)都會被設置。

頁面生命週期的第一個階段是確定運行庫處理當前頁面請求的原因。這個原因有很多種:常規請求、回發、跨頁投遞或回調。基於實際的原因,頁面對象會配置其內部狀態,如果包含被投遞的值,還會根據請求的方法準備該值的集合。在第一個階段過後,頁面便爲引發事件來執行用戶代碼做好了準備。

PreInit事件

這是asp.net引入的事件,它是頁面生命週期的入口點。該事件被引發時,頁面尚未與母版頁和主題相關聯。但頁面滾動條位置已被恢復,被投遞的數據變爲可用,且所有的頁面控件已被實例化,其屬性頁基於在aspx源中的默認值進行了設置(注意,如果沒有在aspx源中顯示指定,這是的控件是沒有ID的),在這個階段中,可以對母版頁進行調換,或對主題進行編程。該事件僅對頁面有效。IsCallBack、IsCrossPagePostBack和IsPostBack會在這時被設置。

Init事件

在這個階段,母版頁和主題(如果存在)會被設定,不能再被更改。頁面處理程序(即Page類的ProcessRequest方法)開始執行,對所有子控件進行迭代,使其有機會在上下文環境下初始化他們的狀態。所有子控件都有自己的OnInit方法,後者以遞歸方式被調用。對於控件集合中的每個控件,都設置有命名容器和特定Id(如果沒有在源中分配)。

Init事件首先會處理子控件,然後是頁面。在這個階段,頁面和控件通常開始加載其部分狀態。此時,視圖狀態尚未被恢復。

InitComplete事件

該事件是asp.net2.0引入的,頁面專有,用於指示初始化子階段的結束。對於頁面來說,在Init和InitComplete事件之間只有一個操作會執行--啓用視圖狀態的變更跟蹤功能。視圖狀態的跟蹤是這樣的一種操作,它最終使控件能夠真正的將所有以編程方式添加到ViewState集合中的值,存儲在持久性介質中。簡而言之,對於沒有實施視圖跟蹤的控件,添加其viewstate中的值將在回髮間丟失。

在控件引發各自的Init事件後,視圖狀態跟蹤會立即啓動,頁面也不例外(歸根結底,頁面也是一種控件)。

(要點:對於上述說明,有一點需要注意:在Initcomplete前,任何寫入viewstate集合中的值,在下一次回發時都不在可用。對於asp,net1.x,必須等待Load事件被引發,才能安全地更改頁面和控件的視圖狀態)。

視圖狀態的恢復

如果頁面因回發而被處理(即IsPostBack屬性爲true),隱藏字段_VIEWSTATE的值會被恢復。隱藏字段_VIEWSTATE用於在請求結束時,保存所有控件的視圖狀態。頁面的整體視圖狀態是一種調用上下文,包含頁面每個組成控件上一次發往瀏覽器的狀態信息。

在這個階段,每個控件會獲得更新其當前狀態的機會,恢復上一次請求時的狀態。視圖狀態恢復過程不會引發任何事件。如果需要對此進行定製,則需藉助於LoadViewState方法的重寫(該方法是Control類中受保護的虛擬成員)。

處理被投遞的數據

Http請求中打包的所有客戶端數據(即所有定義在form標籤中輸入字段的內容)會在這時被處理。被投遞的數據通常採用下面這種形式:

TextBox1=text&DropDownList1=selectedItem$Buttoon1=Submit

該字符串用的鍵值對被“&”分隔。這些值會被加載到一個內部使用的集合中。頁面處理程序會視圖尋找被投遞集合中的名稱與頁面中控件ID的匹配項。如果找到匹配項,處理程序會檢查該服務器控件是否已實現IPostBackDataHandler接口。如果已經實現 ,該接口的方法會被調用,爲使用被投遞數據更新該控件狀態提供機會。具體來講,頁面處理程序會調用該接口的LoadPostData方法。如果他返回true(即,狀態已更新),該控件將被添加到一個獨立的集合中,等待進一步指示。

如果沒有找到與被投遞的名稱對應的服務器控件,它將被擱置於一個臨時的獨立集合中,稍後再試。

PreLoad事件

PreLoad 事件是 asp.net引入的,僅用於指示頁面已完成系統級的初始化,即將進入另一個階段。接下來的階段會爲頁面中用戶代碼的執行提供機會,爲執行和呈現對該頁面進一步配置。只有頁面會引發該事件

Load 事件

Load事件首先由頁面組成,之後以遞歸方式分別由所有的子控件引發。這時,頁面中的控件樹會被創建,各控件的狀態完全反映之前的狀態,並獲得了從客戶端投遞過來的所有數據。對於執行處理邏輯和頁面行爲的初始化代碼,頁面已做好準備。這時訪問控件屬性和視圖狀態是絕對安全的。

處理動態創建的控件

當頁面中所有控件完成了顯示前的初始化後,頁面處理程序會對那些沒有與現有控件相對應的被投遞的數據做再次嘗試。該行爲會對之前擱置的鍵值對再次處理。顯然,這一特殊的方式提供了一種不可思議的特殊方案--使用動態創建的控件。

可以想象,就是講控件動態的添加到頁面的樹中(例如,爲響應某個用戶發出的動作)。如前所述,每次回發,頁面都將要根據原狀態重新生成,因而任何有關動態創建控件的信息會丟失。另一方面,當頁面的窗體提交後,動態控件會被填充合法且有效的信息,並以常規方式投遞。根據設計,初始的動態控件ID不可能與某個服務器控件的ID相匹配。然而asp.net會識別可能在Load 事件中被創建的控件。這樣,在用戶代碼運行一段後,便可以再次嘗試尋找可能的匹配項。

如果動態控件在Load事件中被創建,就可能找到匹配項,從而該控件可以使用被投遞的數據對狀態進行刷新。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章