² 下一個將執(zhí)行的方法是AddParsedSubObject方法,這個方法將添加所有獨立的控件并把頁面組成一個控件集合樹,這個方法經(jīng)常被一些高級的頁面模板解決方案(Page Template Solutions)重寫以便添加頁面內(nèi)容到頁面模板(Page Template)中一些特殊的控件中。這個方法遞歸應(yīng)用到所有的頁面控件及相應(yīng)的的每個子控件,所有的控件都是在這個方法中開始最早的初始化。
² 頁面類中下一個將執(zhí)行的方法是DeterminePostBackMode。這個方法允許您修改IsPostBack的值及相關(guān)的事件。如果您需要從數(shù)據(jù)庫中加載ViewState這個方法將特別有用,因為ViewState只有在IsPostBack為真的情況下才會進(jìn)行恢復(fù)。返回空將會導(dǎo)致強制執(zhí)行非回傳,返回Request.Form則強制執(zhí)行一個回傳。除非在特殊情況下,否則并不建議去操作這個,因為這個還會影響其他的事件。
² 下一個將要執(zhí)行的方法是OnInit方法,一般這是第一個真正被使用的方法。這個方法觸發(fā)時,所有頁面定義中的控件執(zhí)行初始化,這意味著所有在頁面中定義的值應(yīng)用到相應(yīng)的控件上。不過,ViewState和傳回的值還不會應(yīng)用到控件上,因此,任何被代碼或用戶改變的值還沒有被恢復(fù)到控件上。這個方法通常是最好的創(chuàng)建、重創(chuàng)建動態(tài)控件的好地方。
l 恢復(fù)及加載
² 下一個方法,LoadPageStateFromPersistenceMedium只會在頁面被回傳的時候才會被執(zhí)行。如果因為使用Session或自定義存儲方式,您修改了后面將要提到的影響ViewState保存方式的方法SavePageStateToPersistenceMedium,則這個方法需要被重寫。默認(rèn)的實現(xiàn)中ViewState是一種Base64格式編碼,并且被保存在頁面的隱藏域中,您可以使用這篇文章中提及的方法修改ViewState按以上兩種方式保存。注意:這個方法并沒有真正加載ViewState到頁面或頁面控件中。
² 當(dāng)?shù)玫絍iewState后,下一個方法LoadViewSate,將以遞歸的方式恢復(fù)ViewState到頁面及各個頁面控件或子控件中。這個方法執(zhí)行后,每個控件都將恢復(fù)到上一次的狀態(tài),但是用戶提交的數(shù)據(jù)還沒有應(yīng)用到控件上,因為他們不是ViewState的一部分。這個方法主要用于恢復(fù)您在其他事件中動態(tài)生成的控件的值,他們的值是您手動保存在ViewSate中,并且現(xiàn)在已經(jīng)失效。
² 下一個方法是ProcessPostData,這個方法也同樣是回傳的時候才會被執(zhí)行,并且不允許被重寫,這個是頁面基類的私有方法。這個方法通過匹配控件的名稱恢復(fù)相應(yīng)的用戶提交的控件的值,到這一步意味著整個頁面都已經(jīng)被完全恢復(fù)了。唯一要記住的是所有動態(tài)控件的創(chuàng)建必須在這個方法之前。這個方法也是記錄后面的改變事件的方法。
² 下一個方法是OnLoad方法,通常這是用得最多的方法,因為這個方法是頁面生存期第一個恢復(fù)了所有值的地方。大多數(shù)代碼根據(jù)判斷IsPostBack來決定是否重新設(shè)置控件狀態(tài)。您也可以在這個方法中調(diào)用Validate并且檢查IsValid的值。也可以在這個方法中創(chuàng)建動態(tài)控件,并且該控件的所有的方法都會被執(zhí)行以追上當(dāng)前頁面的狀態(tài)包括ViewSate,不過不包括回傳的值。
l 事件處理
² 下一個方法還是ProcessPostData,實際上就是前一個方法的另一次調(diào)用,它仍然是只在回傳的時候執(zhí)行并且由于是私有方法不可以被重寫。如果您是第一次看頁面的運行軌跡也許會覺得這個方法有些多余。但實際上這個方法是必要的因為在OnLoad中創(chuàng)建的動態(tài)控件也需要他們回傳的值。任何在這以后創(chuàng)建的控件將可以得到他們的ViewState,但是不能再得到他們的回傳的值,并且不會觸發(fā)任何值改變事件(Change Event)。
² 下一個方法,RaiseChangedEvents,也是只在回傳頁面中執(zhí)行,并且也因為是基類的私有方法所有不能被繼承。在整個頁面生存期中,是在這兒根據(jù)之前的ProcessPostData記錄的控件的值和提交的值是否不同來觸發(fā)值改變事件。您也許需要調(diào)用Validate或者檢查IsValid的值。這里并沒有特別的說明多個值改變事件的執(zhí)行先后順序。
² 下一個方法,RaisePostBackEvent,同樣是因為是基類的私有方法不能被繼承,同樣也是只在回傳頁面中執(zhí)行。除非使用了AutoPostBack,不然這是實際提交表單事件執(zhí)行的地方,特別是按鈕或者其實使用javascript提交表單等。如果還沒有被手動調(diào)用過并且使用了驗證控件,那么Validate會被調(diào)用。注意IE中有個BUG有時會允許提交但卻不觸發(fā)任何事件。
² 下一個方法是OnPreRender,一般這是在客戶端展現(xiàn)頁面之前改變頁面及其控件的最后一次機會。您也可以在這個方法里面創(chuàng)建動態(tài)控件,并且所有的方法都會被執(zhí)行以追上當(dāng)前頁面的狀態(tài)包括ViewSate,但是私有方法將不會被執(zhí)行,這意味著不會有回傳的值并且不會有事件觸發(fā)。由于IE中的BUG,這是一個沒有事件趕上PostBack的好地方。
l 保存及顯示
² 下一個方法是SaveViewState,不論是否是回傳頁面,均會遞歸的執(zhí)行以保存頁面及其所有控件的ViewState。ViewState基本上保存所有與定義在aspx中的原始值不同的值,不管是被代碼還是用戶所改變。注意控件值是根據(jù)他們在頁面的控件樹中的位置來保存的,所以如果動態(tài)控件后來加到了錯誤的位置將會導(dǎo)致混亂。
² 下一個方法是SavePageStateToPersistenceMedium真正的保存頁面的ViewSate。這個方法隨同LoadPageStateFromPersistenceMediumg 一起被重寫以便保存ViewState到Session或其它自定義數(shù)據(jù),而不是用隱藏域。這對于低帶寬的用戶來說是很有幫助的。并且對于移動設(shè)備來說,Session是默認(rèn)設(shè)置。下面這篇文章描述了使用以上兩種方式保存ViewState的具體細(xì)節(jié)。注意在Asp.net中有個Bug:Asp.net要求必須提交__viewstate字段,即使是空的。
² 下一個方法是Render方法,該方法遞歸的創(chuàng)建并發(fā)送相應(yīng)控件的html給瀏覽器。這個方法被一些頁面模板方案重寫以添加一些通用的頁面頭與腳而不使用服務(wù)器控件,他們總是有一些額外的東西。注意這兒的修改只能使用純HTML,因為控件在這兒已經(jīng)被生成了。您可以用StringBuilder,StringWriter,HtmlTextWriter捕獲相應(yīng)的HTML輸出。
² 最后的方法是OnUnload,這個方法會調(diào)用相應(yīng)的Dispose方法。這個方法提供機會以便清空該頁面中使用的非托管資源,如關(guān)閉打開的文件句柄,以前打開的數(shù)據(jù)庫連接等。注意這個方法是在頁面已經(jīng)發(fā)送到客戶端以后執(zhí)行的,所以它只有影響服務(wù)器對象,并且它不會顯示在頁面的顯示軌跡中。這就是頁面的生存期,對于每一次請求都是這么運行的。
二、精簡版
Page 執(zhí)行中將按照如下順序激活事件:Page.PreInit---->Page.Init---->Page.InitComplite---->Page.PreLoad---->Page.Load---->Page.LoadComplete---->Page.PreRender---->
Page.PreRenderComplete
如果頁面從令一個頁面繼承,如BasePage:System.Web.UI.Page,在BasePage中做了一些擴展,如權(quán)限檢查,而其他頁面從BasePage繼承,則BasePage和最終Page的事件激活順序是:
UI.PreInit---->Page.PreInit---->UI.Init---->Page.Init---->UI.InitComplite---->Page.InitComplite---->UI.PreLoad---->Page.PreLoad---->UI.Load---->Page.Load---->UI.LoadComplete---->Page.LoadComplete---->UI.PreRender---->Page.PreRender---->UI.PreRenderComplete---->Page.PreRenderComplete
如果使用了MasterPage,則MasterPage中的事件和ContentPage中的事件按照下面順序激活:
ContentPage.PreInit
Master.Init
ContentPage.Init
ContentPage.InitComplite
ContentPage.PreLoad
ContentPage.Load
Master.Load
ContentPage.LoadComplete
ContentPage.PreRender
Master.PreRender
ContentPage.PreRenderComplete
更進(jìn)一步,如果ContentPage繼承BasePage,那么,各事件的執(zhí)行順序?qū)⒆兂桑?/span>
UI.PreInit
ContentPage.PreInit
Master.Init
UI.Init
ContentPage.Init
UI.InitComplite
ContentPage.InitComplite
UI.PreLoad
ContentPage.PreLoad
UI.Load
ContentPage.Load
Master.Load
UI.LoadComplete
ContentPage.LoadComplete
UI.PreRender
ContentPage.PreRender
Master.PreRender
UI.PreRenderComplete
ContentPage.PreRenderComplete