上個星期寫了一篇《控件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