日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ZT Web Control 开发系列(一) 页面的生命周期

發布時間:2023/11/29 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ZT Web Control 开发系列(一) 页面的生命周期 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://www.cnblogs.com/joeliu/category/143125.html ??? Page是WebForm編程基本元素,它從TemplateControl派生,而TemplateControl又從Control派生,所以Page實際就是一個Control。同時Page也實現了IHttpHandler接口,所以它可以接受Http請求,進行處理。
????可以認為一個Page是由很多的Control按照樹形結構組織的,而樹的根就是Page(一個實現了IHttphandler的Control), 整個Control樹的生命周期開始于一個Http請求,而終止于請求處理的結束。事實上在Http請求傳入到當前的Page的時候,之前已經經過了漫長的路程,如果對于整個Http請求的細節感興趣,可以查看MSDN中關于應用程序的生命周期。另外關于頁面的生存周期也有很多的文章可以參考,比如MSDN中ASP.NET 頁生命周期概述。
???? 我這里主要講講我個人的理解,如果有什么不妥的地方,歡迎大家指正。
????

??????? Page存在的目的就是對于用戶的內容進行呈現,它是一個IHttpHandler,它實現了對HttpRequest的處理,這個處理的結果就是根據請求Render出它自己,而Render的內容就是Html,CSS,Javascript,這些東西最終成為表現Page樣子的一磚一瓦。如果做一個最簡單的實現,大概就是
public?class?Page?:?IHttpHandler
{
????
public?void?ProcessRequest(HttpContext?httpContext)
????
{
????????Render();
?????}

}

??????? 事實并非如此,如果這樣的話,我們豈不是對于每個Page都要從零開始做一套完整的Render畫法啊,那樣的Render方法將是一個很長,很長的調用,為了支持不同的瀏覽器,為了應付復雜的業務邏輯,里面的代碼將是魔鬼,也許寫完一次沒有人愿意維護了,而且代碼的復用性也很低。那么怎么辦呢?.net為了解決這個問題,提供的是Control模型,對于一個頁面,頁面本身是一個可以呈現自己的Control,同事頁面里面也可以任意嵌套其它的Control,每個Control都具有呈現自己的能力,那樣Control將具有很好的復用性和可維護性,任何一個開發人員可以任意組合來自于第三方的Control來構建自己的Page。所以就需要有一個Control的類,而且Page是Control的一個派生類。Page的Render方法需要遞歸調用RenderChildren,這樣讓整個Control樹一層一層的呈現,最后得到整個Page的樣子。

??????? 我們知道Http請求里面有Get和Post,對于Get往往是請求一個全新的頁面,對于Post更多的是客戶端的一個響應。對于Get的請求,我們可以從零開始Render一個新的Page給客戶端。但是對于Post,我們一般需要讓頁面恢復到客戶端看到的狀態,然后再出來Post的數據。正是由于這個原因,Page在ProcessRequest的過程中不得不區分Page.IsPost or not。而如何進行場景恢復呢,這大概就是ViewState產生的真正原因了,ViewState是Control上的一個存儲結構。它負責保存Control的一些狀態。這些狀態通常會被序列化到客戶端的頁面上,當客戶端的頁面發出Post請求的時候,.net生產的腳本會自動收集這些ViewState數據,然后一起Post給服務器端。這樣Page就可以加載這些狀態進行場景恢復,然后在恢復好的場景下出來PostData。所以在ProcessRequest里面需要加入對于LoadViewState,SaveViewState,ProcessPostData的處理。

??????? 但是是否所有對于Control的設置都會序列化成ViewState呢,那樣不是很影響性能嗎,如果說我們每次在請求處理的開始階段(無論是Post還是非Post)都用代碼初始化Control,不是就不需要利用ViewState加載狀態了啊?所以在ProcessRequest里面又有了新的過程的加入Init,在Init里面可以設置Control的一些屬性和狀態,而在Init以后才通過TrackViewState來通知Control,TrackViewState階段后對Control的修改才會SaveViewState的時候保存下來,否則都不保存。

??????? 類似的例子還有很多,就像我們自己做的軟件產品,很多時候,第一個版本都是簡單的,以后隨著需求的增加,代碼越來越多,結構越來越復雜,也許未來版本的Page還會有更多的變化,總之經過很多的需求,Page對于Request的處理就變得復雜了,最后就分為下面的幾個階段,關于這些階段的介紹,我們可以在Google上搜索很多的文章,我認為我們不僅僅要了解這些階段,還要深入理解,否則想做出好的Control是很困難的。代碼中的數字列出了主要的頁面生命周期的階段,對于PostBack和CallBack,階段會發生一些變化,也加了說明
private?void?ProcessRequestMain(bool?includeStagesBeforeAsyncPoint,?bool?includeStagesAfterAsyncPoint)
????
{
????????
//?1.?PreInit
????????this.PerformPreInit();
????????
//?2.?Init
????????this.InitRecursive(null);
????????
this.OnInitComplete(EventArgs.Empty);

????????
//?對于Postback,插入下面處理
????????if?(this.IsPostBack)
????????
{
????????????
//?加載ViewState和ControlState,進行場景恢復
????????????this.LoadAllState();
????????????
//?第一次處理PostData
????????????this.ProcessPostData(this._requestValueCollection,?true);
????????}


????????
//?3.?PreLoad
????????this.OnPreLoad(EventArgs.Empty);
????????
//?4.?Load
????????this.LoadRecursive();

????????
//?對于Postback,插入下面處理
????????if?(this.IsPostBack)
????????
{
????????????
//?第二次處理PostData
????????????this.ProcessPostData(this._leftoverPostData,?false);
????????????
//?如果PostData表面某個Control數據發生變化,那么RaisePostDataChanged事件
????????????this.RaiseChangedEvents();
????????????
//?RaisePostBackEvent
????????????this.RaisePostBackEvent(this._requestValueCollection);
????????}


????????
this.OnLoadComplete(EventArgs.Empty);

????????
//?對于CallBack,RaiseCallBackEvent
????????if?(this.IsPostBack?&&?this.IsCallback)
????????
{
????????????
this.PrepareCallback(callbackControlID);
????????}

????????
else?if?(!this.IsCrossPagePostBack)
????????
{
????????????
//?5.?PreRender
????????????this.PreRenderRecursiveInternal();
????????}

???
????????
//?對于CallBack,?Render出CallBack的結果
????????if?(this.IsCallback)
????????
{
????????????
this.RenderCallback();
????????}

????????
else?if?(!this.IsCrossPagePostBack)
????????
{
????????????
this.PerformPreRenderComplete();
????????????
????????????
//?6.?SaveViewStae和ControlState
????????????this.SaveAllState();
????????????
this.OnSaveStateComplete(EventArgs.Empty);

????????????
//?7.?Render?整個Control
????????????this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
????????}

????}

1. PreInit 階段
??? 這個階段是Page獨有的,在Control上是沒有的,這個階段主要是.net Framework自己在里面做了一些自己的初始化工作,比如Skin的加載,MasterPage的加載。會發Page.OnPreInit事件,源代碼如下:
private?void?PerformPreInit()
{
????
this.OnPreInit(EventArgs.Empty);
????
this.InitializeThemes();
????
this.ApplyMasterPage();
????
this._preInitWorkComplete?=?true;
}


2. Init階段
??? InitRecursive()是Page從Control繼承的方法,它主要進行Control的一些初始化和標記工作
??? a.? 對當前Control進行準確初始化,包括:
  • 初始化_adapter;
  • ApplySkin(this.Page);
  • 設置標記this._controlState = ControlState.Initialized;
  • TrackViewState()//開始跟蹤變化,這個階段以后的變化會存入ViewState
??? b.? 對子Control進行初始化
  • 初始化nameContainer屬性
  • 初始化page屬性
  • 自動生成Id
  • 遞歸調用子Control的InitRecursive()方法

????? 有個值得注意的是,如果在Control樹執行完Init之后創建一個新的Control加入到樹上,那么當它加入的時候,在父Control的AddedControl方法里面,如果發現已經Initialized,那么手動調用新加入Control的InitRecursive()方法。
??? 所以,我們Control的Init階段給Control的一些需要查找才可以得到的屬性進行直接賦值,如Page,nameContainer,這樣可以提高這些屬性的訪問速度。

3. PreLoad階段
?? 僅僅發Page獨有的事件:OnPreLoad事件

4. Load階段
?? LoadRecursive()是Page從Control繼承的方法,它比較簡單,僅僅是遞歸調用子Control的LoadRecursive()方法,然后做一個階段標記: (this._controlState = ControlState.Loaded);

5. PreRender階段
??? PreRenderRecursiveInternal()是Page從Control繼承的方法,這個方法會

  • EnsureChildControls()-->調用CreateChildControls(),確保子Control創建完畢,為接下來的Render做準備
  • 遞歸調用子Control的PreRenderRecursiveInternal()??

6. SaveAllState 階段
??? 主要存儲ControlState和ViewState,ControlState和ViewState唯一不同的地方在于ControlState是不可以禁用的,而ViewState可以禁用,事實上.net Framework在ControlState里面還加入了一個數據,這個數據是一個ArrayList,里面存入了所有的需要處理PostData的Control的Id,這樣在Post階段,.net Framework會根據ArrayList里面保存的Control來依次調用ProcessPostData方法,前提是這些Control最好實現IPostDataHandler接口。

7. Render階段
?? RenderControl()是Page從Control繼承的方法,這個方法會遞歸調用子Control的RenderControl (),這樣一層一層進行呈現。

總結:
??? Init,Load,PreRender,SaveState,Render這幾個階段會在整個Control樹上遞歸貫穿。在Init里面對Control的修改,一般是不會保存到ViewState里面,這個階段以后的變化會存入ViewState。
??? LoadAllState發生在Init和Load之間,因為LoadState會進行場景恢復,所以如果我們在Page_Load里面進行了一些初始化工作,那么如果在Post階段就不需要二次初始化了,所以經常會寫這樣的代碼 if (Page.IsPostBack) {...; // Init Controls},真正的原因就在這里了。
?? 另外也有一些在Load事件里面動態創建Control的做法,這個時候也要小心了。因為LoadAllState只會加載ViewState數據包,并不會創建Control(人家也不知道你的Control什么類型啊),所以無論是否IsPostBack,Control都需要創建并且加入到Controls集合。如果在Post階段,當Control一加入集合,就會被調用InitRecursive()方法進行初始化,同時還會把父Control上保存的該Control的ViewState傳給它,讓它加載。關于加載ViewState的知識也比較復雜,有安裝Control Index加載和安裝Control Id加載兩種,細節可以在以后專題講述。

補充:關于一個Control的生和死

Control的生可以分為兩種,一種是在DesignMode下設計好,一旦一個請求到來,Page被創建,這個時候Control就已經添加到以Page為根的Control樹了,所以它可以經歷完整的頁面生命周期(Init, Load。。。);另一種是在頁面生命周期的某個階段創建,例如Init的時候,或者Load的時候,這個時候.net為了繼續保持Control能經歷頁面的整個生命周期,會在它被加入到Control樹的瞬間進行一些補充式的調用,具體實現可以看下面的Control.AddedControl方法。

?

protected?internal?virtual?void?AddedControl(Control?control,?int?index)
{
????
//?1.?初始化Page,Parent,NameContainer,ID
????control._parent?=?this;
????control._page?
=?this.Page;
????control.flags.Clear(
0x20000);
????Control?namingContainer?
=?this.flags[0x80]???this?:?this._namingContainer;
????
if?(namingContainer?!=?null)
????
{
????????control.UpdateNamingContainer(namingContainer);
????????
if?((control._id?==?null)?&&?!control.flags[0x40])
????????
{
????????????control.GenerateAutomaticID();
????????}

????????
else?if?((control._id?!=?null)?||?((control._occasionalFields?!=?null)?&&?(control._occasionalFields.Controls?!=?null)))
????????
{
????????????namingContainer.DirtyNameTable();
????????}

????}


????
//?2.?判斷當前Control所在的頁面生命周期階段,然后對于新加入的Control進行補充調用
????if?(this._controlState?>=?ControlState.ChildrenInitialized)
????
{
????????control.InitRecursive(namingContainer);
????????
if?(((control._controlState?>=?ControlState.Initialized)?&&?(control.RareFields?!=?null))?&&?control.RareFields.RequiredControlState)
????????
{
????????????
this.Page.RegisterRequiresControlState(control);
????????}

????????
if?(this._controlState?>=?ControlState.ViewStateLoaded)
????????
{
????????????
object?savedState?=?null;
????????????
if?((this._occasionalFields?!=?null)?&&?(this._occasionalFields.ControlsViewState?!=?null))
????????????
{
????????????????savedState?
=?this._occasionalFields.ControlsViewState[index];
????????????????
if?(this.LoadViewStateByID)
????????????????
{
????????????????????control.EnsureID();
????????????????????savedState?
=?this._occasionalFields.ControlsViewState[control.ID];
????????????????????
this._occasionalFields.ControlsViewState.Remove(control.ID);
????????????????}

????????????????
else
????????????????
{
????????????????????savedState?
=?this._occasionalFields.ControlsViewState[index];
????????????????????
this._occasionalFields.ControlsViewState.Remove(index);
????????????????}

????????????}

????????????control.LoadViewStateRecursive(savedState);
????????????
if?(this._controlState?>=?ControlState.Loaded)
????????????
{
????????????????control.LoadRecursive();
????????????????
if?(this._controlState?>=?ControlState.PreRendered)
????????????????
{
????????????????????control.PreRenderRecursiveInternal();
????????????????}

????????????}

????????}

????}

}


同樣,Control的死也可以分為兩種,一種就是完整的經歷一個頁面請求,.net會在所有的請求都處理完了之后,也就是在我上面講的所有的階段之后調用一個ProcessRequestClearUp()方法,另外一種就是在頁面的生命周期的某個階段調用Controls.Remove(control)方法來干掉Control,在這個調用發生后,父Control有一個叫做RemovedControl的方法會調用(和上面的AddedControl是兄弟哦),來進行清理工作,其實現基本是上面AddedControl的反操作。

值得注意的是,無論是RemovedControl()還是ProcessRequestClearUp(),它們都在Control還沒有從Control樹上摘掉的時候,調用了一個非常重要的方法control.UnloadRecursive(),這個方法從最底層的子Control向上直到當前正在移除的Control,依次執行OnUnload()方法,所以做WebControl的時候,我們可以override on_Unload()方法,在這個方法里面,可以摘除Event,摘除與Control樹關聯的變量,做一些清理工作。這點是非常有用的。


后記:從來沒有往首頁上發布過我的帖子。當我昨天發布了前言后發現很多人對這個話題都很感興趣,一方面感覺高興,一方面也感覺壓力,畢竟我沒有寫過什么像樣的技術文章,生怕辜負大家厚望。最近白天工作忙,只能晚上在家好好整理思路寫出來。因為對于寫WebControl的基本方法已經有很多地方介紹了(比如《道不遠人》),也沒有重復一遍的必要,所以我主要寫寫我對WebForm主要實現的理解。我認為這是我們設計一個專業的WebControl的基本功。有什么寫的不清楚的地方,歡迎大家指正,我一定盡力補充。

轉載于:https://www.cnblogs.com/limxc/archive/2008/07/22/1249070.html

總結

以上是生活随笔為你收集整理的ZT Web Control 开发系列(一) 页面的生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。