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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

}

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

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

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

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

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


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

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


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

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

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

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

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

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

????}

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


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

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

3. PreLoad階段
?? 僅僅發(fā)Page獨(dú)有的事件:OnPreLoad事件

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

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

  • EnsureChildControls()-->調(diào)用CreateChildControls(),確保子Control創(chuàng)建完畢,為接下來的Render做準(zhǔn)備
  • 遞歸調(diào)用子Control的PreRenderRecursiveInternal()??

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

7. Render階段
?? RenderControl()是Page從Control繼承的方法,這個(gè)方法會(huì)遞歸調(diào)用子Control的RenderControl (),這樣一層一層進(jìn)行呈現(xiàn)。

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

補(bǔ)充:關(guān)于一個(gè)Control的生和死

Control的生可以分為兩種,一種是在DesignMode下設(shè)計(jì)好,一旦一個(gè)請(qǐng)求到來,Page被創(chuàng)建,這個(gè)時(shí)候Control就已經(jīng)添加到以Page為根的Control樹了,所以它可以經(jīng)歷完整的頁面生命周期(Init, Load。。。);另一種是在頁面生命周期的某個(gè)階段創(chuàng)建,例如Init的時(shí)候,或者Load的時(shí)候,這個(gè)時(shí)候.net為了繼續(xù)保持Control能經(jīng)歷頁面的整個(gè)生命周期,會(huì)在它被加入到Control樹的瞬間進(jìn)行一些補(bǔ)充式的調(diào)用,具體實(shí)現(xiàn)可以看下面的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.?判斷當(dāng)前Control所在的頁面生命周期階段,然后對(duì)于新加入的Control進(jìn)行補(bǔ)充調(diào)用
????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的死也可以分為兩種,一種就是完整的經(jīng)歷一個(gè)頁面請(qǐng)求,.net會(huì)在所有的請(qǐng)求都處理完了之后,也就是在我上面講的所有的階段之后調(diào)用一個(gè)ProcessRequestClearUp()方法,另外一種就是在頁面的生命周期的某個(gè)階段調(diào)用Controls.Remove(control)方法來干掉Control,在這個(gè)調(diào)用發(fā)生后,父Control有一個(gè)叫做RemovedControl的方法會(huì)調(diào)用(和上面的AddedControl是兄弟哦),來進(jìn)行清理工作,其實(shí)現(xiàn)基本是上面AddedControl的反操作。

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


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

轉(zhuǎn)載于:https://www.cnblogs.com/limxc/archive/2008/07/22/1249070.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。