ASP.NET 頁生命週期概述
ASP.NET 頁運行時,此頁將經曆一個生命週期,在生命週期中將執行一系列處理步驟。這些步驟包括初始化、執行個體化控制項、還原和維護狀態、運行事件處理常式代碼以及進行呈現。瞭解頁生命週期非常重要,因為這樣做您就能在生命週期的合適階段編寫代碼,以達到預期效果。此外,如果您要開發自訂控制項,就必須熟悉頁生命週期,以便正確進行控制項初始化,使用檢視狀態資料填充控制項屬性以及運行任何控制項行為代碼。(控制項的生命週期基於頁的生命週期,但是頁引發的控制項事件比單獨的 ASP.NET 頁中可用的事件多。) 常規頁生命週期階段
一般來說,頁要經曆下表概述的各個階段。除了頁生命週期階段以外,在請求前後還存在應用程式階段,但是這些階段並不特定於頁。有關更多資訊,請參見 ASP.NET 應用程式生命週期概述。
| 階段 |
說明 |
| 頁請求 |
頁請求發生在頁生命週期開始之前。使用者請求頁時,ASP.NET 將確定是否需要分析和編譯頁(從而開始頁的生命週期),或者是否可以在不運行頁的情況下發送頁的緩衝版本以進行響應。 |
| 開始 |
在開始階段,將設定頁屬性,如 Request 和 Response。在此階段,頁還將確定請求是回傳請求還是新請求,並設定 IsPostBack 屬性。此外,在開始階段期間,還將設定頁的 UICulture 屬性。 |
| 頁初始化 |
頁初始化期間,可以使用頁中的控制項,並將設定每個控制項的 UniqueID 屬性。此外,任何主題都將應用於頁。如果當前請求是回傳請求,則回傳資料尚未載入,並且控制項屬性值尚未還原為檢視狀態中的值。 |
| 載入 |
載入期間,如果當前請求是回傳請求,則將使用從檢視狀態和控制項狀態恢複的資訊載入控制項屬性。 |
| 驗證 |
在驗證期間,將調用所有驗證程式控制項的 Validate 方法,此方法將設定各個驗證程式控制項和頁的 IsValid 屬性。 |
| 回傳事件處理 |
如果請求是回傳請求,則將調用所有事件處理常式。 |
| 呈現 |
在呈現之前,會針對該頁和所有控制項儲存檢視狀態。在呈現階段中,頁會針對每個控制項調用 Render 方法,它會提供一個文本編寫器,用於將控制項的輸出寫入頁的 Response 屬性的 OutputStream 中。 |
| 卸載 |
完全呈現頁並已將頁發送至用戶端、準備丟棄該頁後,將調用卸載。此時,將卸載頁屬性(如 Response 和 Request)並執行清理。 |
生命週期事件
在頁生命週期的每個階段中,頁將引發可運行您自己的代碼進行處理的事件。對於控制項事件,通過以聲明方式使用屬性(如 onclick)或以使用代碼的方式,均可將事件處理常式綁定到事件。
頁還支援自動事件串連,即,ASP.NET 將尋找具有特定名稱的方法,並在引發了特定事件時自動運行這些方法。如果 @ Page 指令的 AutoEventWireup 屬性設定為 true(或者未定義該屬性,因為該屬性預設為 true),頁事件將自動綁定至使用 Page_事件的命名規範的方法(如 Page_Load 和 Page_Init)。有關自動事件串連的更多資訊,請參見 ASP.NET Web 伺服器控制項事件模型。
下表列出了最常用的頁生命週期事件。除了列出的事件外還有其他事件;不過,大多數頁處理方案不使用這些事件。而是主要由 ASP.NET 網頁上的伺服器控制項使用,以初始化和呈現它們本身。如果要編寫自己的 ASP.NET 伺服器控制項,則需要詳細瞭解這些階段。有關建立自訂控制項的資訊,請參見開發自訂 ASP.NET 伺服器控制項。
| 頁事件 |
典型使用 |
| PreInit |
使用該事件來執行下列操作: 檢查 IsPostBack 屬性來確定是不是第一次處理該頁。 建立或重新建立動態控制項。 動態設定主控頁。 動態設定 Theme 屬性。 讀取或設定設定檔屬性值。
| 注意 |
| 如果請求是回傳請求,則控制項的值尚未從檢視狀態還原。如果在此階段設定控制項屬性,則其值可能會在下一事件中被重寫。 |
|
| Init |
在所有控制項都已初始化且已應用所有外觀設定後引發。使用該事件來讀取或初始化控制項屬性。 |
| InitComplete |
由 Page 對象引發。使用該事件來處理要求先完成所有初始化工作的任務。 |
| PreLoad |
如果需要在 Load 事件之前對頁或控制項執行處理,請使用該事件。 在 Page 引發該事件後,它會為自身和所有控制項載入檢視狀態,然後會處理 Request 執行個體包括的任何回傳資料。 |
| Load |
Page 在 Page 上調用 OnLoad 事件方法,然後以遞迴方式對每個子控制項執行相同操作,如此迴圈往複,直到載入完本頁和所有控制項為止。 使用 OnLoad 事件方法來設定控制項中的屬性並建立資料庫連接。 |
| 控制項事件 |
使用這些事件來處理特定控制項事件,如 Button 控制項的 Click 事件或 TextBox 控制項的 TextChanged 事件。
| 注意 |
| 在回傳請求中,如果頁包含驗證程式控制項,請在執行任何處理之前檢查 Page 和各個驗證控制項的 IsValid 屬性。 |
|
| LoadComplete |
對需要載入頁上的所有其他控制項的任務使用該事件。 |
| PreRender |
在該事件發生前: Page 對象會針對每個控制項和頁調用 EnsureChildControls。 設定了 DataSourceID 屬性的每個資料繫結控制項會調用 DataBind 方法。有關更多資訊,請參見下面的資料繫結控制項的資料繫結事件。 頁上的每個控制項都會發生 PreRender 事件。使用該事件對頁或其控制項的內容進行最後更改。 |
| SaveStateComplete |
在該事件發生前,已針對頁和所有控制項儲存了 ViewState。將忽略此時對頁或控制項進行的任何更改。 使用該事件執行滿足以下條件的任務:要求已經儲存了檢視狀態,但未對控制項進行任何更改。 |
| Render |
這不是事件;在處理的這個階段,Page 對象會在每個控制項上調用此方法。所有 ASP.NET Web 伺服器控制項都有一個用於寫出發送給瀏覽器的控制項標記的 Render 方法。 如果建立自訂控制項,通常要重寫此方法以輸出控制項的標記。不過,如果自訂控制項只合并標準的 ASP.NET Web 伺服器控制項,不合并自訂標籤,則不需要重寫 Render 方法。有關更多資訊,請參見開發自訂 ASP.NET 伺服器控制項。 使用者控制項(.ascx 檔案)自動合并呈現,因此不需要在代碼中顯式呈現該控制項。 |
| Unload |
該事件首先針對每個控制項發生,繼而針對該頁發生。在控制項中,使用該事件對特定控制項執行最後清理,如關閉控制項特定資料庫連接。 對於頁自身,使用該事件來執行最後清理工作,如:關閉開啟的檔案和資料庫連接,或完成日誌記錄或其他請求特定任務。
| 注意 |
| 在卸載階段,頁及其控制項已被呈現,因此無法對響應流做進一步更改。如果嘗試調用方法(如 Response.Write 方法),則該頁將引發異常。 |
|
其他的頁生命週期注意事項
各個 ASP.NET 伺服器控制項都有自己的生命週期,該生命週期與頁生命週期類似。例如,控制項的 Init 和 Load 事件在相應的頁事件期間發生。
雖然 Init 和 Load 都在每個控制項上以遞迴方式發生,但它們的發生順序相反。每個子控制項的 Init 事件(還有 Unload 事件)在為其容器引發相應的事件之前發生(由下到上)。但是,容器的 Load 事件是在其子控制項的 Load 事件之前發生(由上到下)。
可以通過處理控制項的事件(如 Button 控制項的 Click 事件和 ListBox 控制項的 SelectedIndexChanged 事件)來自訂控制項的外觀或內容。在某些情況下,可能也需處理控制項的 DataBinding 或 DataBound 事件。有關更多資訊,請參見各個控制項的類參考主題以及開發自訂 ASP.NET 伺服器控制項。
當從 Page 類繼承類時,除了可以處理由頁引發的事件以外,還可以重寫頁的基類中的方法。例如,可以重寫頁的 InitializeCulture 方法,以便動態設定地區性資訊。注意,在使用 Page_事件文法建立事件處理常式時,將隱式調用基實現,因此無需在方法中調用它。例如,無論是否建立 Page_Load 方法,始終都會調用頁基類的 OnLoad 方法。但是,如果使用 override 關鍵字(在 Visual Basic 中為 Overrides)重寫頁的 OnLoad 方法,則必須顯式調用基方法。例如,如果在頁中重寫 OnLoad 方法,則必須調用 base.Load(在 Visual Basic 中為 MyBase.Load)以運行基實現。 添加的控制項的追趕事件
如果控制項是在運行時動態建立的,或者是以聲明方式在資料繫結控制項的模板中建立的,它們的事件最初與頁上的其他控制項的事件並不同步。例如,對於運行時添加的控制項,Init 和 Load 事件在頁生命週期中的發生時間可能要比以聲明方式建立的控制項的相同事件晚得多。因此,從執行個體化那一刻起,動態添加的控制項的事件就一直是在模板中的控制項的事件之後發生,直到趕上該控制項加入 Controls 集合時所對應事件為止。
一般來說,除非存在嵌套資料繫結控制項,否則,您不必擔心這種情況。如果子控制項已執行資料繫結,但其容器控制項尚未執行資料繫結,則子控制項中的資料與其容器控制項中的資料可能不同步。如果子控制項中的資料根據容器控制項中的資料繫結值執行了處理,這種情況則尤其顯著。
例如,假定有一個 GridView,它的每一行顯示一條公司記錄,此外,有一個 ListBox 控制項包含公司管理者列表。若要填充管理者列表,則需要將 ListBox 控制項綁定到一個資料來源控制項(如 SqlDataSource),後者在查詢中使用 CompanyID 來檢索公司管理者資料。
如果以聲明方式設定了 ListBox 控制項的資料繫結屬性(如 DataSourceID 和 DataMember),ListBox 控制項將嘗試在包含行的 DataBinding 事件期間綁定到其資料來源。不過,行的 CompanyID 欄位直到 GridView 控制項的 RowDataBound 事件發生後才包含值。這種情況下,先綁定子控制項(ListBox 控制項),後綁定包含控制項(GridView 控制項),因此它們的資料繫結階段並不同步。
若要避免此種情況,需要將 ListBox 控制項的資料來源控制項與 ListBox 控制項自身放在同一模板項中,並且不要以聲明方式設定 ListBox 的資料繫結屬性。而應在 RowDataBound 事件期間在運行時以編程方式設定它們,這樣,到 CompanyID 資訊可用時 ListBox 控制項才會綁定到其資料。
有關更多資訊,請參見使用資料來源控制項綁定到資料。 資料繫結控制項的資料繫結事件
為了協助您理解頁生命週期與資料繫結事件之間的關係,下表列出了資料繫結控制項(如 GridView、DetailsView 和 FormView 控制項)中與資料相關的事件。
| 控制項事件 |
典型使用 |
| DataBinding |
該事件在包含控制項(或 Page 對象)的 PreRender 事件之前由資料繫結控制項引發,會標記控制項到資料的綁定過程的起點。 如果需要,使用該事件以手動方式開啟資料庫連接。(資料來源控制項通常不需要如此操作。) |
| RowCreated(僅限 GridView)或 ItemCreated(DataList、DetailsView、SiteMapPath、DataGrid、FormView 和 重複器控制項) |
使用該事件來操作不依賴於資料繫結的內容。例如,在運行時,可以以編程方式向 GridView 控制項中的頁首或頁尾行添加格式。 |
| RowDataBound(僅限 GridView)或 ItemDataBound(DataList、SiteMapPath、DataGrid 和 Repeater 控制項) |
當該事件發生時,行或項中的資料可用,因此,可以在子資料來源控制項上格式化資料或設定 FilterExpression 屬性,以便顯示行或項中的相關資料。 |
| DataBound |
該事件在資料繫結控制項中標記資料繫結操作的結尾。在 GridView 控制項中,會針對所有行和任何子控制項完成資料繫結。 使用該事件格式化資料繫結內容,或在依賴來自當前控制項的內容的值的其他控制項中啟動資料繫結。(有關詳細資料,請參見本主題中前面的“添加的控制項的追趕事件”。) |
登入控制項事件 Login 控制項可以使用 Web.config 檔案中的設定來自動管理成員資格驗證。不過,如果應用程式要求您自訂控制項的工作方式,或者您要瞭解 Login 控制項事件與頁生命週期的關聯方式,可以使用下表中列出的事件。
| 控制項事件 |
典型使用 |
| LoggingIn |
在回傳期間,當頁的 LoadComplete 事件發生後就會引發該事件。它標記登入過程的起點。 對必須在驗證過程開始前發生的任務使用該事件。 |
| Authenticate |
該事件在 LoggingIn 事件之後引發。 使用該事件來重寫或增強 Login 控制項的預設驗證行為。 |
| LoggedIn |
該事件在驗證使用者名稱和密碼後引發。 使用該事件來重新導向到另一個頁或動態設定控制項中的文本。如果出現錯誤或驗證失敗,就不會發生該事件。 |
| LoginError |
如果驗證失敗,將引發該事件。 使用該事件來設定控制項中的問題解釋文本或將使用者定向到不同的頁。 |
請參見 參考 在 ASP.NET 網頁中驗證使用者輸入
ASP.NET 登入控制項概述
概念 ASP.NET Web 伺服器控制項事件模型
ASP.NET Web 應用程式中的頁和應用程式上下文
檢視狀態概述
使用資料來源控制項綁定到資料
其他資源 開發自訂 ASP.NET 伺服器控制項
ASP.NET 頁文法
ASP.NET 網頁中的伺服器事件處理