當(dāng)一個(gè)頁(yè)面請(qǐng)求發(fā)送到WEB服務(wù)器時(shí),不論該事件是由頁(yè)面提交還是由頁(yè)面重定向而激發(fā)的,頁(yè)面在其被創(chuàng)建到釋放的過程中都會(huì)運(yùn)行一系列的事件。一個(gè)ASP.NET頁(yè)面從被創(chuàng)建到釋放的過程包含10個(gè)事件。
?。?)對(duì)象初始化Init事件:頁(yè)面初始化的標(biāo)志是Init事件。頁(yè)面中的控件(包括頁(yè)面本身)都是在它們最初的Form中被首次初始化的。在成功創(chuàng)建頁(yè)面的控件樹后,對(duì)應(yīng)用程序激發(fā)這個(gè)事件。當(dāng)Init事件發(fā)生時(shí),在.aspx源文件中靜態(tài)聲明的所有控件都以實(shí)例化并取其默認(rèn)值。應(yīng)該注意到,這是還沒有視圖狀態(tài)信息可供使用。雖然可以重載OnInit方法,但是系統(tǒng)并不保證這些控件實(shí)例是按照怎樣的順序被創(chuàng)建的。
(2)加載視圖:在初始化之后,頁(yè)面框架立即加載該頁(yè)面的視圖狀態(tài)(ViewState)。所謂視圖狀態(tài)就是一些名稱/值對(duì)的集合,例如可以保存TextBox控件的ID和Text屬性值。它一般被用于在一個(gè)往返行程中存留信息到服務(wù)器,即參與HTTP請(qǐng)求與響應(yīng)。
頁(yè)面視圖狀態(tài)被存儲(chǔ)在<input type=”hidden”>字段中,做為_VIEWSTAE的值進(jìn)行記錄。該視圖狀態(tài)通過ASP.NE自動(dòng)維護(hù)。通過重寫LoadViewState方法組件,開發(fā)人員可控制如何還原視圖狀態(tài)以及如何將其內(nèi)容影射到內(nèi)部狀態(tài)。LoadViewState方法就是從ViewState中獲取上一次的狀態(tài),并按照頁(yè)面的控件樹的結(jié)構(gòu),用遞歸來遍歷整個(gè)樹,將對(duì)應(yīng)的狀態(tài)恢復(fù)到每一個(gè)控件上。
?。?)處理回發(fā)數(shù)據(jù):還原了視圖狀態(tài),頁(yè)面樹種的各個(gè)控件的狀態(tài)就與瀏覽器上次呈現(xiàn)該頁(yè)面時(shí)這些控件所處的狀態(tài)相同。下一步需要更新這些控件的狀態(tài)以發(fā)送給客戶端。
回發(fā)數(shù)據(jù)處理階段是各個(gè)控件有機(jī)會(huì)更新其狀態(tài),以便準(zhǔn)確的反映相應(yīng)的HTML元素在客戶端的狀態(tài)。例如,一個(gè)服務(wù)器TextBox控件對(duì)應(yīng)的HTML元素是<input type=text>,在回發(fā)數(shù)據(jù)階段,TextBox控件將檢索<input>標(biāo)記的當(dāng)前值并用它刷新其內(nèi)部狀態(tài)。每個(gè)控件負(fù)責(zé)從以發(fā)送的數(shù)據(jù)中提取相應(yīng)值,并更新其某些屬性。TextBox控件將更新Text屬性,而CheckBox控件將刷新其Checked屬性。服務(wù)器控件和HTML元素之間的匹配關(guān)系由二者的ID確定。
頁(yè)框架將在每個(gè)提交數(shù)據(jù)的控件上實(shí)現(xiàn)IpostBackDataHandler接口,然后激發(fā)LoadPostData事件,通過頁(yè)面解析發(fā)現(xiàn)實(shí)現(xiàn)了IpostBackDataHandle接口的控件,這樣就能正確的回傳數(shù)據(jù)更新控件狀態(tài)。在識(shí)別控件時(shí),ASP.NET通過匹配控件的唯一標(biāo)示符來更新正確的控件,該標(biāo)識(shí)符具有名稱值集和中的名稱值對(duì)。這也就是在所有特定的頁(yè)中每個(gè)控件都需要一個(gè)唯一標(biāo)識(shí)符的原因之一。其他的步驟都由框架來完成,例如確定每個(gè)標(biāo)識(shí)符在環(huán)境中是否唯一以及控件的基本屬性等。
LostPostData方法的原型如下:
Public virtual bool LoadPostData(string postDatakey, NameValueCollection postCollection)
PostDataKey是標(biāo)識(shí)控件的關(guān)鍵字,可以理解為控件的ID,postCollection是包含回發(fā)數(shù)據(jù)的集合,可以理解為視圖狀態(tài)值。該方法返回一個(gè)bool值,如果是true,則表示控件狀態(tài)因回發(fā)而更改;否則返回false。頁(yè)框架會(huì)更跟蹤所有返回true的控件并在這些控件上調(diào)用RaisePostDataChangeEvent事件。
LoadPostData方法是由System..Web.WebControls.Control定義的,而添加的每一個(gè)服務(wù)器控件也是從System..Web.WebControls.Control繼承的,所以對(duì)于數(shù)據(jù)的回發(fā)處理并不需要干預(yù)。
?。?)加載頁(yè)面Load:在回發(fā)數(shù)據(jù)處理階段結(jié)束時(shí),頁(yè)面中的所有控件都根據(jù)客戶端上所輸入的更改來更新的狀態(tài)。此時(shí),對(duì)頁(yè)面激發(fā)OnLoad事件。對(duì)于這個(gè)事件,相信大多數(shù)朋友都會(huì)比較熟悉,用Visual Studio.Net生成的頁(yè)面中的Page_Load方法就是響應(yīng)Load事件的方法,對(duì)于每一次請(qǐng)求,Load事件都會(huì)觸發(fā),Page_Load方法也就會(huì)執(zhí)行??梢岳迷摲椒▓?zhí)行一些頁(yè)面初始化,例如準(zhǔn)備好數(shù)據(jù)庫(kù)的連接字符串。在事件引用中,為了提高性能,通常使用Page類的IsPostBack屬性判斷是不是數(shù)據(jù)回發(fā)。
?。?)回發(fā)更改通知RaisePostDataChanged:如(3)所述,在所有實(shí)現(xiàn)了IpostBackDataHandler接口的控件被正確的回傳數(shù)據(jù)更新后,每個(gè)控件都有一個(gè)布爾值的標(biāo)識(shí),標(biāo)識(shí)其自上一次提交后改控件的數(shù)據(jù)是被更改還是保持其值。然后ASP.NET通過搜索頁(yè)來尋找任何顯示控件數(shù)據(jù)被更改的標(biāo)識(shí)并激發(fā)RaisePostDataChanged。RaisePostDataChanged事件直到Load事件發(fā)生后,所有控件被更新后才激發(fā)。這保證了在控件被回傳數(shù)據(jù)更新前,其他控件的數(shù)據(jù)在RaisePostDataChanged事件中沒有被手動(dòng)更改過。雖然也可以在Page的基礎(chǔ)上自己定義數(shù)據(jù)更改的事件,但通常這個(gè)事件由太大用處。
?。?)處理回發(fā)事件RaisePostBackEvent:當(dāng)回傳更新導(dǎo)致數(shù)據(jù)改變而引發(fā)服務(wù)器端事件后,引發(fā)回傳的對(duì)象會(huì)在RaisePostBackEvent事件中被處理。這種引發(fā)回傳的對(duì)象往往是一個(gè)按鈕被單擊或者其狀態(tài)改變而引發(fā)回傳的控件。例如Button觸發(fā)樂Onclick事件、客戶端修改了某個(gè)文本框的文本、同時(shí)將AutoPostBack設(shè)置為true、觸發(fā)TextChanged事件等。
很多代碼都在這個(gè)事件中執(zhí)行,因?yàn)檫@是控制事件驅(qū)動(dòng)邏輯的理想位置。為了保證呈現(xiàn)到瀏覽器的數(shù)據(jù)的正確性,在一系列的回傳事件后,RaisePostBackEvent事件最終被激發(fā)?;谝恢滦钥紤],會(huì)傳中改變的控件直到這個(gè)函數(shù)被執(zhí)行后才被更新。在實(shí)際的ASP.NET開發(fā)工作中要做的工作就是在此事件發(fā)生前處理代碼。
(7) 預(yù)呈現(xiàn)PreRender:在處理回發(fā)事件后,頁(yè)面就準(zhǔn)備進(jìn)行呈現(xiàn)。這一階段的標(biāo)志是PreRender事件。各個(gè)控件可利用這個(gè)很好的時(shí)機(jī),以便執(zhí)行任何需要在保存視圖狀態(tài)和呈現(xiàn)輸出結(jié)果的前一刻完成得最后一些更新操作。最終請(qǐng)求的處理都會(huì)轉(zhuǎn)變?yōu)榘l(fā)揮服務(wù)器的響應(yīng),預(yù)呈現(xiàn)這個(gè)階段就是執(zhí)行在最終呈現(xiàn)之前所做的狀態(tài)的更改,因?yàn)樵诔尸F(xiàn)一個(gè)控件之前,必須更具它的屬性來產(chǎn)生HTML,比如Style屬性。這是典型的例子,這預(yù)呈現(xiàn)之前,可以更改一個(gè)控件的Style,當(dāng)執(zhí)行預(yù)呈現(xiàn)時(shí),就可以把Style保存下來,做為呈現(xiàn)階段顯示HTML的樣式信息。
(8)保存狀態(tài)SaveViewState:下一個(gè)狀態(tài)為SaveViewState,在這一狀態(tài)中所有控件以及頁(yè)面本身可以刷新自己的SaveState集合的內(nèi)容。所得到的視圖狀態(tài)隨后得以序列化、進(jìn)行哈希運(yùn)算、進(jìn)行Base64編碼并關(guān)聯(lián)到VI-EMSTATE隱藏自端。
?。?)呈現(xiàn)視圖Render:到這里,實(shí)際上頁(yè)面對(duì)請(qǐng)求的處理基本就告一段落了,在Render事件中,也調(diào)用對(duì)象是它們呈現(xiàn)為HTML,然后也收集HTML發(fā)送給客戶??蛻艚邮盏紿TML標(biāo)記后進(jìn)行重組,最終顯示給客戶。當(dāng)Render事件被重載時(shí),開發(fā)者可以為瀏覽器創(chuàng)建定值的HTML,此時(shí)頁(yè)面創(chuàng)建的任何HTML都還沒有生效。Render方法用HtmlTextWriter對(duì)象做參數(shù)并由它產(chǎn)生HTML送給瀏覽器。這主要用于自定義控件的開發(fā)。
?。?0)處置Disposed:執(zhí)行銷毀控件前的所有最終清理操作。在此階段必須釋放對(duì)昂貴資源的引用,如內(nèi)存的退出、數(shù)據(jù)庫(kù)的連接等。
?。?1)卸載Unload:一個(gè)頁(yè)面的最后生存標(biāo)志就是Unload事件,該事件在頁(yè)面對(duì)象被解除之前發(fā)生。在此事件中,可以調(diào)用Dispose方法盡可能釋放占用的任何關(guān)鍵資源(例如,文件、圖形對(duì)象以及數(shù)據(jù)庫(kù)連接)。
聯(lián)系客服