ASP.NET 頁(yè)運行時(shí),此頁(yè)將經(jīng)歷一個(gè)生命周期,在生命周期中將執行一系列處理步驟。這些步驟包括初始化、實(shí)例化控件、還原和維護狀態(tài)、運行事件處理程序代碼以及進(jìn)行呈現。了解頁(yè)生命周期非常重要,因為這樣做您就能在生命周期的合適階段編寫(xiě)代碼,以達到預期效果。此外,如果您要開(kāi)發(fā)自定義控件,就必須熟悉頁(yè)生命周期,以便正確進(jìn)行控件初始化,使用視圖狀態(tài)數據填充控件屬性以及運行任何控件行為代碼。(控件的生命周期基于頁(yè)的生命周期,但是頁(yè)引發(fā)的控件事件比單獨的 ASP.NET 頁(yè)中可用的事件多。)
常規頁(yè)生命周期階段
一般來(lái)說(shuō),頁(yè)要經(jīng)歷下表概述的各個(gè)階段。除了頁(yè)生命周期階段以外,在請求前后還存在應用程序階段,但是這些階段并不特定于頁(yè)。有關(guān)更多信息,請參見(jiàn) ASP.NET 應用程序生命周期概述。
| 階段 | 說(shuō)明 |
|---|---|
| 頁(yè)請求 | 頁(yè)請求發(fā)生在頁(yè)生命周期開(kāi)始之前。用戶(hù)請求頁(yè)時(shí),ASP.NET 將確定是否需要分析和編譯頁(yè)(從而開(kāi)始頁(yè)的生命周期),或者是否可以在不運行頁(yè)的情況下發(fā)送頁(yè)的緩存版本以進(jìn)行響應。 |
| 開(kāi)始 | 在開(kāi)始階段,將設置頁(yè)屬性,如 Request 和 Response。在此階段,頁(yè)還將確定請求是回發(fā)請求還是新請求,并設置 IsPostBack 屬性。此外,在開(kāi)始階段期間,還將設置頁(yè)的 UICulture 屬性。 |
| 頁(yè)初始化 | 頁(yè)初始化期間,可以使用頁(yè)中的控件,并將設置每個(gè)控件的 UniqueID 屬性。此外,任何主題都將應用于頁(yè)。如果當前請求是回發(fā)請求,則回發(fā)數據尚未加載,并且控件屬性值尚未還原為視圖狀態(tài)中的值。 |
| 加載 | 加載期間,如果當前請求是回發(fā)請求,則將使用從視圖狀態(tài)和控件狀態(tài)恢復的信息加載控件屬性。 |
| 驗證 | 在驗證期間,將調用所有驗證程序控件的 Validate 方法,此方法將設置各個(gè)驗證程序控件和頁(yè)的 IsValid 屬性。 |
| 回發(fā)事件處理 | 如果請求是回發(fā)請求,則將調用所有事件處理程序。 |
| 呈現 | 在呈現之前,會(huì )針對該頁(yè)和所有控件保存視圖狀態(tài)。在呈現階段中,頁(yè)會(huì )針對每個(gè)控件調用 Render 方法,它會(huì )提供一個(gè)文本編寫(xiě)器,用于將控件的輸出寫(xiě)入頁(yè)的 Response 屬性的 OutputStream 中。 |
| 卸載 | 完全呈現頁(yè)并已將頁(yè)發(fā)送至客戶(hù)端、準備丟棄該頁(yè)后,將調用卸載。此時(shí),將卸載頁(yè)屬性(如 Response 和 Request)并執行清理。 |
生命周期事件
在頁(yè)生命周期的每個(gè)階段中,頁(yè)將引發(fā)可運行您自己的代碼進(jìn)行處理的事件。對于控件事件,通過(guò)以聲明方式使用屬性(如 onclick)或以使用代碼的方式,均可將事件處理程序綁定到事件。
頁(yè)還支持自動(dòng)事件連接,即,ASP.NET 將查找具有特定名稱(chēng)的方法,并在引發(fā)了特定事件時(shí)自動(dòng)運行這些方法。如果 @ Page 指令的 AutoEventWireup 屬性設置為 true(或者未定義該屬性,因為該屬性默認為 true),頁(yè)事件將自動(dòng)綁定至使用 Page_事件的命名約定的方法(如 Page_Load 和 Page_Init)。有關(guān)自動(dòng)事件連接的更多信息,請參見(jiàn) ASP.NET Web 服務(wù)器控件事件模型。
下表列出了最常用的頁(yè)生命周期事件。除了列出的事件外還有其他事件;不過(guò),大多數頁(yè)處理方案不使用這些事件。而是主要由 ASP.NET 網(wǎng)頁(yè)上的服務(wù)器控件使用,以初始化和呈現它們本身。如果要編寫(xiě)自己的 ASP.NET 服務(wù)器控件,則需要詳細了解這些階段。有關(guān)創(chuàng )建自定義控件的信息,請參見(jiàn)開(kāi)發(fā)自定義 ASP.NET 服務(wù)器控件。
| 頁(yè)事件 | 典型使用 | ||
|---|---|---|---|
| 使用該事件來(lái)執行下列操作:
| |||
| 在所有控件都已初始化且已應用所有外觀(guān)設置后引發(fā)。使用該事件來(lái)讀取或初始化控件屬性。 | |||
| 由 Page 對象引發(fā)。使用該事件來(lái)處理要求先完成所有初始化工作的任務(wù)。 | |||
| 如果需要在 Load 事件之前對頁(yè)或控件執行處理,請使用該事件。 在 Page 引發(fā)該事件后,它會(huì )為自身和所有控件加載視圖狀態(tài),然后會(huì )處理 Request 實(shí)例包括的任何回發(fā)數據。 | |||
| Load | Page 在 Page 上調用 OnLoad 事件方法,然后以遞歸方式對每個(gè)子控件執行相同操作,如此循環(huán)往復,直到加載完本頁(yè)和所有控件為止。 使用 OnLoad 事件方法來(lái)設置控件中的屬性并建立數據庫連接。 | ||
| 控件事件 | 使用這些事件來(lái)處理特定控件事件,如 Button 控件的 Click 事件或 TextBox 控件的 TextChanged 事件。
| ||
| 對需要加載頁(yè)上的所有其他控件的任務(wù)使用該事件。 | |||
| 在該事件發(fā)生前:
頁(yè)上的每個(gè)控件都會(huì )發(fā)生 PreRender 事件。使用該事件對頁(yè)或其控件的內容進(jìn)行最后更改。 | |||
| 在該事件發(fā)生前,已針對頁(yè)和所有控件保存了 ViewState。將忽略此時(shí)對頁(yè)或控件進(jìn)行的任何更改。 使用該事件執行滿(mǎn)足以下條件的任務(wù):要求已經(jīng)保存了視圖狀態(tài),但未對控件進(jìn)行任何更改。 | |||
| Render | 這不是事件;在處理的這個(gè)階段,Page 對象會(huì )在每個(gè)控件上調用此方法。所有 ASP.NET Web 服務(wù)器控件都有一個(gè)用于寫(xiě)出發(fā)送給瀏覽器的控件標記的 Render 方法。 如果創(chuàng )建自定義控件,通常要重寫(xiě)此方法以輸出控件的標記。不過(guò),如果自定義控件只合并標準的 ASP.NET Web 服務(wù)器控件,不合并自定義標記,則不需要重寫(xiě) Render 方法。有關(guān)更多信息,請參見(jiàn)開(kāi)發(fā)自定義 ASP.NET 服務(wù)器控件。 用戶(hù)控件(.ascx 文件)自動(dòng)合并呈現,因此不需要在代碼中顯式呈現該控件。 | ||
| 該事件首先針對每個(gè)控件發(fā)生,繼而針對該頁(yè)發(fā)生。在控件中,使用該事件對特定控件執行最后清理,如關(guān)閉控件特定數據庫連接。 對于頁(yè)自身,使用該事件來(lái)執行最后清理工作,如:關(guān)閉打開(kāi)的文件和數據庫連接,或完成日志記錄或其他請求特定任務(wù)。
|
其他的頁(yè)生命周期注意事項
各個(gè) ASP.NET 服務(wù)器控件都有自己的生命周期,該生命周期與頁(yè)生命周期類(lèi)似。例如,控件的 Init 和 Load 事件在相應的頁(yè)事件期間發(fā)生。
雖然 Init 和 Load 都在每個(gè)控件上以遞歸方式發(fā)生,但它們的發(fā)生順序相反。每個(gè)子控件的 Init 事件(還有 Unload 事件)在為其容器引發(fā)相應的事件之前發(fā)生(由下到上)。但是,容器的 Load 事件是在其子控件的 Load 事件之前發(fā)生(由上到下)。
可以通過(guò)處理控件的事件(如 Button 控件的 Click 事件和 ListBox 控件的 SelectedIndexChanged 事件)來(lái)自定義控件的外觀(guān)或內容。在某些情況下,可能也需處理控件的 DataBinding 或 DataBound 事件。有關(guān)更多信息,請參見(jiàn)各個(gè)控件的類(lèi)參考主題以及開(kāi)發(fā)自定義 ASP.NET 服務(wù)器控件。
當從 Page 類(lèi)繼承類(lèi)時(shí),除了可以處理由頁(yè)引發(fā)的事件以外,還可以重寫(xiě)頁(yè)的基類(lèi)中的方法。例如,可以重寫(xiě)頁(yè)的 InitializeCulture 方法,以便動(dòng)態(tài)設置區域性信息。注意,在使用 Page_事件語(yǔ)法創(chuàng )建事件處理程序時(shí),將隱式調用基實(shí)現,因此無(wú)需在方法中調用它。例如,無(wú)論是否創(chuàng )建 Page_Load 方法,始終都會(huì )調用頁(yè)基類(lèi)的 OnLoad 方法。但是,如果使用 override 關(guān)鍵字(在 Visual Basic 中為 Overrides)重寫(xiě)頁(yè)的 OnLoad 方法,則必須顯式調用基方法。例如,如果在頁(yè)中重寫(xiě) OnLoad 方法,則必須調用 base.Load(在 Visual Basic 中為 MyBase.Load)以運行基實(shí)現。
添加的控件的追趕事件
如果控件是在運行時(shí)動(dòng)態(tài)創(chuàng )建的,或者是以聲明方式在數據綁定控件的模板中創(chuàng )建的,它們的事件最初與頁(yè)上的其他控件的事件并不同步。例如,對于運行時(shí)添加的控件,Init 和 Load 事件在頁(yè)生命周期中的發(fā)生時(shí)間可能要比以聲明方式創(chuàng )建的控件的相同事件晚得多。因此,從實(shí)例化那一刻起,動(dòng)態(tài)添加的控件的事件就一直是在模板中的控件的事件之后發(fā)生,直到趕上該控件加入 Controls 集合時(shí)所對應事件為止。
一般來(lái)說(shuō),除非存在嵌套數據綁定控件,否則,您不必擔心這種情況。如果子控件已執行數據綁定,但其容器控件尚未執行數據綁定,則子控件中的數據與其容器控件中的數據可能不同步。如果子控件中的數據根據容器控件中的數據綁定值執行了處理,這種情況則尤其顯著(zhù)。
例如,假定有一個(gè) GridView,它的每一行顯示一條公司記錄,此外,有一個(gè) ListBox 控件包含公司管理者列表。若要填充管理者列表,則需要將 ListBox 控件綁定到一個(gè)數據源控件(如 SqlDataSource),后者在查詢(xún)中使用 CompanyID 來(lái)檢索公司管理者數據。
如果以聲明方式設置了 ListBox 控件的數據綁定屬性(如 DataSourceID 和 DataMember),ListBox 控件將嘗試在包含行的 DataBinding 事件期間綁定到其數據源。不過(guò),行的 CompanyID 字段直到 GridView 控件的 RowDataBound 事件發(fā)生后才包含值。這種情況下,先綁定子控件(ListBox 控件),后綁定包含控件(GridView 控件),因此它們的數據綁定階段并不同步。
若要避免此種情況,需要將 ListBox 控件的數據源控件與 ListBox 控件自身放在同一模板項中,并且不要以聲明方式設置 ListBox 的數據綁定屬性。而應在 RowDataBound 事件期間在運行時(shí)以編程方式設置它們,這樣,到 CompanyID 信息可用時(shí) ListBox 控件才會(huì )綁定到其數據。
有關(guān)更多信息,請參見(jiàn)使用數據源控件綁定到數據。
數據綁定控件的數據綁定事件
為了幫助您理解頁(yè)生命周期與數據綁定事件之間的關(guān)系,下表列出了數據綁定控件(如 GridView、DetailsView 和 FormView 控件)中與數據相關(guān)的事件。
| 控件事件 | 典型使用 |
|---|---|
| DataBinding | 該事件在包含控件(或 Page 對象)的 PreRender 事件之前由數據綁定控件引發(fā),會(huì )標記控件到數據的綁定過(guò)程的起點(diǎn)。 如果需要,使用該事件以手動(dòng)方式打開(kāi)數據庫連接。(數據源控件通常不需要如此操作。) |
| RowCreated(僅限 GridView)或 ItemCreated(DataList、DetailsView、SiteMapPath、DataGrid、FormView 和 Repeater 控件) | 使用該事件來(lái)操作不依賴(lài)于數據綁定的內容。例如,在運行時(shí),可以以編程方式向 GridView 控件中的頁(yè)眉或頁(yè)腳行添加格式。 |
| RowDataBound(僅限 GridView)或 ItemDataBound(DataList、SiteMapPath、DataGrid 和 Repeater 控件) | 當該事件發(fā)生時(shí),行或項中的數據可用,因此,可以在子數據源控件上格式化數據或設置 FilterExpression 屬性,以便顯示行或項中的相關(guān)數據。 |
| DataBound | 該事件在數據綁定控件中標記數據綁定操作的結尾。在 GridView 控件中,會(huì )針對所有行和任何子控件完成數據綁定。 使用該事件格式化數據綁定內容,或在依賴(lài)來(lái)自當前控件的內容的值的其他控件中啟動(dòng)數據綁定。(有關(guān)詳細信息,請參見(jiàn)本主題中前面的“添加的控件的追趕事件”。) |
登錄控件事件
Login 控件可以使用 Web.config 文件中的設置來(lái)自動(dòng)管理成員資格驗證。不過(guò),如果應用程序要求您自定義控件的工作方式,或者您要了解 Login 控件事件與頁(yè)生命周期的關(guān)聯(lián)方式,可以使用下表中列出的事件。
| 控件事件 | 典型使用 |
|---|---|
| 在回發(fā)期間,當頁(yè)的 LoadComplete 事件發(fā)生后就會(huì )引發(fā)該事件。它標記登錄過(guò)程的起點(diǎn)。 對必須在驗證過(guò)程開(kāi)始前發(fā)生的任務(wù)使用該事件。 | |
| 該事件在 LoggingIn 事件之后引發(fā)。 使用該事件來(lái)重寫(xiě)或增強 Login 控件的默認驗證行為。 | |
| 該事件在驗證用戶(hù)名和密碼后引發(fā)。 使用該事件來(lái)重定向到另一個(gè)頁(yè)或動(dòng)態(tài)設置控件中的文本。如果出現錯誤或驗證失敗,就不會(huì )發(fā)生該事件。 | |
| 如果驗證失敗,將引發(fā)該事件。 使用該事件來(lái)設置控件中的問(wèn)題解釋文本或將用戶(hù)定向到不同的頁(yè)。 |


