上個星期寫了一篇《控件 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.cnblogs.com/cathsfz/archive/2006/10/29/543695.Html