天天看點

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事件中被建立,就可能找到比對項,進而該控件可以使用被投遞的資料對狀态進行重新整理。