介紹ASP.NET頁面生命周期
ASP.NET頁面生命周期
在面對此類問題的時(shí)候,首先問問自己控件的數(shù)量,如果數(shù)量不多,直接通過設(shè)置控件的Visible屬性解決問題就是了。這也就是說,把可能要顯示的控件都聲明為Visible="false",然后在代碼中判斷當(dāng)前應(yīng)該將哪個(gè)顯示出來。
如果控件比較多,然而還是能分組的,同一時(shí)間僅僅顯示其中的一組,那么你應(yīng)該考慮使用MultiView,這樣你的工作將會(huì)輕松不少。事實(shí)上,能夠使用 MultiView解決的,都應(yīng)該優(yōu)先考慮使用MultiView解決,這比起自己控制哪一個(gè)控件顯示哪一個(gè)控件隱藏要方便多了。其實(shí)MultiView 所做的,也就是幫你控制控件的顯示與隱藏。
這樣做的性能如何呢?我們關(guān)注兩方面的問題,一方面是服務(wù)器端執(zhí)行的資源消耗,另一方面是傳輸?shù)膸捪摹N覀兿葋砜纯捶?wù)器端執(zhí)行的資源消耗吧,我們最常見的消耗應(yīng)該就是數(shù)據(jù)控件操作數(shù)據(jù)庫時(shí)的消耗了。在ASP.NET 1.x時(shí)代,我們沒有數(shù)據(jù)源控件,所以必須手動(dòng)進(jìn)行DataBind(),這也就是說如果不手動(dòng)執(zhí)行DataBind()的話就不會(huì)進(jìn)行任何數(shù)據(jù)操作,因此只要我們記得在數(shù)據(jù)控件不顯示的時(shí)候也不要讓它執(zhí)行DataBind()就是了,那樣就不會(huì)有性能損失。在ASP.NET 2.0當(dāng)中,使用數(shù)據(jù)源控件的話數(shù)據(jù)控件是會(huì)自動(dòng)DataBind()的,這時(shí)候會(huì)造成控件隱藏時(shí)的資源消耗呢?事實(shí)上是不會(huì)的,數(shù)據(jù)控件即使已經(jīng)定義了 DataSourceID屬性,它也僅僅在自己***次可見時(shí)才進(jìn)行自動(dòng)DataBind()。如果數(shù)據(jù)控件的狀態(tài)是隱藏的(包括使用MultiView隱藏),它就不會(huì)自動(dòng)進(jìn)行DataBind()。因此,在ASP.NET 2.0中使用數(shù)據(jù)源控件以及MultiView之后其底層過程還是和ASP.NET 1.x手動(dòng)操作的一樣,就是少寫一些代碼而已。
我們接著來看看帶寬消耗如何,因?yàn)殡[藏的控件不輸出任何的HTML,因此帶寬消耗就是指ViewState了??丶[藏后,ViewState是不變的,因此隱藏控件確實(shí)比完全不加載控件造成了更多的資源消耗,換取的是該控件的狀態(tài)得以保存。一般來說,簡單控件隱藏后多出來幾十字節(jié)的ViewState是可以忽略不計(jì)的,整個(gè)頁面中HTML縮進(jìn)所需的空格也都幾十上百字節(jié)了;但如果是復(fù)雜控件,擁有大量的ViewState,這時(shí)候你真的應(yīng)該考慮動(dòng)態(tài)加載了。
總的來說,面對這類問題時(shí)首先判斷顯示隱藏控件的邏輯是否復(fù)雜,控件本身是否復(fù)雜。如果是比較簡單的情況,則直接使用 MultiView解決就是了。如果是復(fù)雜的情況,那就應(yīng)該考慮自己使用控件將此邏輯封裝在內(nèi),而不是直接在頁面上暴露這些復(fù)雜性。關(guān)于封裝控件的問題,在下一篇文章中再討論,因此我們繼續(xù)看下一類問題。
既不確定類型也不確定數(shù)量的控件
有時(shí)候我們面對前面兩類問題都有清晰的思路,但是面對復(fù)合問題就感覺很混亂了。例如還是一個(gè)調(diào)查問卷的顯示,數(shù)據(jù)來自XML,問題類型包括單選和多選,每一道問題的選項(xiàng)個(gè)數(shù)也不確定,這時(shí)候怎么辦呢?foreach嵌套foreach,外層迭代問題內(nèi)層迭代選項(xiàng),逐個(gè)CheckBox/RadioButton來生成?
這時(shí)候我們需要的是把問題分而治之逐個(gè)擊破的思想。既然是上述兩類問題的嵌套,我們就應(yīng)該能夠通過嵌套對應(yīng)的解決方案來實(shí)現(xiàn)。對于這個(gè)調(diào)查問卷的例子,我們可以用Repeater來迭代問題,先把這個(gè)定下來,再考慮模板里面怎么做。模板里面需要顯示的是一個(gè)不確定類型的問題,因此模板里面放一個(gè) MutliView,把問題類型的表達(dá)式綁定到其ActiveViewIndex屬性上,例如單選題就是0多選題就是1。然后MultiView里面的兩個(gè)View各自嵌套一個(gè)Repeater,第0個(gè)Repeater迭代選項(xiàng)并顯示為RadioButton,第1個(gè)Repeater迭代選項(xiàng)并顯示為 CheckBox。就這樣就完成了,我們沒寫任何一行后臺(tái)代碼,也沒有動(dòng)態(tài)創(chuàng)建任何控件。
然后我們來分析一下這個(gè)解決方案的性能。對比起動(dòng)態(tài)創(chuàng)建控件,它所使用的控件確實(shí)是多了一倍,因?yàn)橐坏绬栴}同時(shí)創(chuàng)建了兩組選項(xiàng),一組單選一組多選,只不過其中一組被隱藏了。然而隱藏掉的那一組唯一的服務(wù)器端資源消耗就是創(chuàng)建以及綁定,它們不輸出任何的HTML,因?yàn)樗鼈兊闹挡粫?huì)被改變所以也不會(huì)輸出任何的ViewState,并且它們也不會(huì)觸發(fā)任何事件,因此在對性能沒有特別要求的情況下這樣的性能損失還是可以接受的。至少,這比起你自己去研究ASP.NET頁面生命周期然后自己寫一大段代碼來實(shí)現(xiàn)動(dòng)態(tài)加載控件要好多了。
問題與實(shí)驗(yàn)
本系列上一篇文章的問題與實(shí)驗(yàn)一直沒有解答,現(xiàn)在給出參考答案如下:
1.為Page增加一個(gè)ShowCheckBox的屬性:
- bool ShowCheckBox {
- get { return (ViewState["ShowCheckBox"] == null) ?
false : (bool)ViewState["ShowCheckBox"]; }- set { ViewState["ShowCheckBox"] = value; }
- }
在OnLoad的時(shí)候檢測ShowCheckBox屬性,如果為true則添加上該CheckBox控件。在Button的 OnClick事件中,設(shè)置ShowCheckBox為true,并添加上CheckBox。記得這兩處創(chuàng)建的CheckBox必須擁有一致的ID屬性。
2. 這是為了讓ICallbackEventHandler的處理模型符合ASP.NET頁面生命周期的模型。雖然Callback發(fā)生的時(shí)候,ASP.NET頁面生命周期已經(jīng)與PostBack不同,然而ICallbackEventHandler還是讓Callback模仿了PostBack的頁面生命周期。RaiseCallbackEvent相當(dāng)于PostBack的Raise PostBackEvent階段,GetCallbackResult相當(dāng)于PostBack的PreRender階段。前者負(fù)責(zé)事件響應(yīng),后者負(fù)責(zé)生成返回客戶端的HTML代碼。
這次想和大家討論的問題是,你覺得你是***主義者嗎?面對上面的調(diào)查問卷需求,你會(huì)選擇我所說的Repeater套MultiView再套R(shí)epeater的做法,從而避免寫任何一行后臺(tái)代碼,還是會(huì)選擇自己封裝一個(gè)控件動(dòng)態(tài)創(chuàng)建所有控件,避免任何不必要的性能損失?
【編輯推薦】