上個星期寫了一篇《控件 ViewState 屬性的值保存去哪里了》,解釋了Control.ViewState最終還是通過Control.SaveViewState和Control.LoadViewState這兩個方法存取的。文章中有一句話可能會讓大家感到疑惑的:“我們在OnInit之后使用this.ViewState[key]讀寫時該屬性都為true”,其中“該屬性”指StateItem.IsDirty。到底為什么IsDirty屬性在OnInit之后總是為true呢?參考了TRULY Understanding ViewState,我終于明白到其實它并非總是為true,詳細原因請聽我慢慢說。
首先要讓大家來看的是StateBag.TrackViewState方法,這個方法在控件OnInit時就會被調用,而它的作用就是讓StateBag開始跟蹤StateItem的變化,任何變化都將導致該StateItem的IsDirty屬性變為true。也就是說,在OnInit之前,IsDirty屬性是false的,并且無論你如何設置Value屬性的值都不會改變IsDirty屬性。在OnInit之后,IsDirty屬性也保持著false,直到你第一次改變Value屬性的值(指通過this.ViewState[key]的方法改變)。到了SaveViewState的階段,只有IsDirty屬性為true的StateItem才會被保存下來。
為什么要如此設計呢?例如一個通過聲明性定義的Label的Text屬性,在aspX中它被賦了初值,然后該初值自然通過ViewState["Text"]來持久。在下一個頁面生命周期,首先OnInit時這個Label的Text屬性會加載ASPX中聲明性定義的初值,然后LoadViewState時會用ViewState中讀取到的ViewState["Text"]來覆蓋它。然而除非你在上一個頁面生命周期以編程的方式改變了Text屬性,否則ViewState["Text"]還是初值,那么你就是用ViewState["Text"]保存初值去覆蓋聲明性定義的初值,同一個值這樣覆蓋完全沒意義,而且還浪費了ViewState的空間。為了解決這個資源浪費的問題,凡是聲明性定義之后沒改變到的值就不應該使用ViewState來持久,而詳細的實現就是上面說的TrackViewState機制了。
說到這里,Control.ViewState已經解釋完畢,如果你是控件設計者你可以放心地按以下方式把控件屬性存放到ViewState中:
public string Text
{
get {return this.ViewState["Text"] as string;}
set {this.ViewState["Text"] = value;}
}
它的內部機制會懂得區分你存進去的值是不是ASPX上聲明性定義的初值,然后決定是否持久該值。同時,如果你在任何階段想改變一個ViewState值是否持久的決定,可以通過ViewState.SetItemDirty(key, dirty)來改變,這基本上已經滿足了所有控件開發人員的需求。
http://www.survivalescaperooms.com/cathsfz/archive/2006/10/29/543695.html
新聞熱點
疑難解答