自定義視圖狀態(tài)管理
在介紹視圖狀態(tài)時(shí),我們?cè)?jīng)提到過(guò):對(duì)于簡(jiǎn)單屬性,例如,String、Int等類型,.NET執(zhí)行引擎將自動(dòng)啟用默認(rèn)視圖狀態(tài)管理機(jī)制,以便完成相應(yīng)的功能。然而,如果開(kāi)發(fā)人員在ViewState中保存的是自定義數(shù)據(jù)類型,或者需要實(shí)現(xiàn)自定義方式優(yōu)化視圖狀態(tài)管理時(shí),則必須實(shí)現(xiàn)自定義視圖狀態(tài)管理。
實(shí)現(xiàn)自定義視圖狀態(tài)管理可以通過(guò)兩種方法。方法一:實(shí)現(xiàn)System.Web.UI命名空間中的IStateManager接口成員,其中包括IsTrackingViewState屬性和TrackViewState、SaveViewState和LoadViewState方法。這種方法主要是針對(duì)自定義數(shù)據(jù)類型的視圖狀態(tài)管理的情況。方法二:重寫(xiě)Control基類的3個(gè)視圖狀態(tài)管理方法:TrackViewState、SaveViewState和LoadViewState。這些方法與IStateManager接口定義的3個(gè)方法名稱一致。這種方法主要用于通過(guò)自定義方式優(yōu)化默認(rèn)視圖狀態(tài)管理的情況,其主要目的在于提高效率和性能。掌握以上兩種實(shí)現(xiàn)方法的捷徑是,必須深刻理解.NET框架內(nèi)部實(shí)現(xiàn)視圖狀態(tài)管理的過(guò)程。下面兩小節(jié)內(nèi)容都是有關(guān)內(nèi)部實(shí)現(xiàn)方法的介紹。每一節(jié)中均有實(shí)現(xiàn)代碼,實(shí)際就相當(dāng)于實(shí)例代碼。所有服務(wù)器控件的自定義視圖狀態(tài)管理的實(shí)現(xiàn)都不會(huì)偏離那些代碼所表達(dá)的邏輯。當(dāng)讀者真正掌握了那些內(nèi)部實(shí)現(xiàn)方法,那么自定義視圖狀態(tài)管理的實(shí)現(xiàn)方法也就迎刃而解了。
1、實(shí)現(xiàn)基于IStateManager接口的自定義視圖狀態(tài)管理
對(duì)于復(fù)雜屬性而言,多數(shù)需要實(shí)現(xiàn)自定義視圖狀態(tài)管理,其關(guān)鍵是實(shí)現(xiàn)System.Web.UI.IStateManager接口中定義的方法和屬性。下面列舉了IStateManager接口定義代碼。
如上代碼所示,IStateManager接口要求類實(shí)現(xiàn)IsTrackingViewState屬性,以及LoadViewState、SaveViewState和TrackViewState方法。IsTrackingViewState屬性定義,當(dāng)由類實(shí)現(xiàn)時(shí),獲取一個(gè)布爾值,通過(guò)該值指示服務(wù)器控件是否正在跟蹤其視圖狀態(tài)更改。如果服務(wù)器控件正在跟蹤其視圖狀態(tài)更改,則為true;否則為false。SaveViewState方法定義,當(dāng)由類實(shí)現(xiàn)時(shí),將服務(wù)器控件的視圖狀態(tài)更改保存到Object中。LoadViewState方法定義,當(dāng)由類實(shí)現(xiàn)時(shí),加載服務(wù)器控件以前保存的控件視圖狀態(tài),其中的參數(shù)state表示包含控件保存的視圖狀態(tài)值的Object。TrackViewState方法定義,當(dāng)由類實(shí)現(xiàn)時(shí),指示服務(wù)器控件跟蹤其視圖狀態(tài)更改。
ViewState屬性與IStateManager接口之間存在密切聯(lián)系。ViewState屬性的類型是StateBag類,StateBag類通過(guò)實(shí)現(xiàn)IStateManager接口中定義的方法和屬性來(lái)參與狀態(tài)管理。其實(shí)現(xiàn)過(guò)程如下。
private bool _isTrackingViewState;
private ArrayList _keys;
private ArrayList _values;
private StateItem _item;
bool IStateManager.IsTrackingViewState {
get { return _isTrackingViewState; }
}
void IStateManager.TrackViewState() {
_isTrackingViewState = true;
}
object IStateManager.SaveViewState() {
_keys = new ArrayList();
_values = new ArrayList();
IDictionaryEnumerator myDirctionaryEnumerator = this.GetEnumerator();
while(myDictionaryEnumerator.MoveNext()) {
if(this.Item[(String)myDictionaryEnumerator.Key].IsDirty) {
_keys.Add(myDictionaryEnumerator.Key);
_values.Add(myDictionaryEnumerator.Value);
}
}
if(_keys.Count>0) {
return new Pair(_keys,_values);
}
}
void IStateManager.LoadViewState(object savedState) {
if(savedState is Pair) {
_keys = (ArrayList)tempP.First;
_values = (ArrayList)tempP.Second;
IDictionaryEnumerator myDirctionaryEnumerator = this.GetEnumerator();
while(myDictionaryEnumerator.MoveNext()) {
for(int j=0;j<_keys.Count;j++)
{
if((String)myDictionaryEnumerator.Key == _keys[j].ToString());
{
this.Item[_keys[j].ToString()].Value = (object)_values[j];
}
}
}
}
}
}
請(qǐng)讀者注意:以上代碼為示意性代碼,并非嚴(yán)格意義上的實(shí)現(xiàn)代碼。在此列出,主要是用于說(shuō)明StateBag類實(shí)現(xiàn)IStateManager接口的邏輯過(guò)程。
通過(guò)上面的代碼,我們可以看到:
(1)在IsTrackingViewState屬性中,將該屬性設(shè)置為只讀,并且使用私有變量_isTrackingViewState。
(2)在TrackViewState方法中,把IsTrackingViewState屬性使用的私有變量_isTrackingViewState設(shè)置為true,這指示系統(tǒng)當(dāng)某個(gè)StateItem添加到StateBag中,或者某個(gè)StateItem值被修改時(shí),StateBag類就會(huì)自動(dòng)將該StateItem標(biāo)記為修改過(guò)即添加dirty標(biāo)記。
(3)在SaveViewState方法中,循環(huán)StateBag中的每個(gè)StateItem,如果該StateItem被標(biāo)記為dirty,那么就將其鍵和值分別添加到兩個(gè)ArrayList中,并返回該對(duì)象。
(4)在LoadViewState方法中,執(zhí)行了與SaveViewState方法相反的操作。首先將savedState對(duì)象分解為兩個(gè)保存有鍵和值的ArrayList,然后將其中的值加載到相應(yīng)的StateItem對(duì)象中。
以上就是ViewState屬性實(shí)現(xiàn)IStateManager接口的基本過(guò)程。所有的視圖狀態(tài)管理過(guò)程,都要使用以上的實(shí)現(xiàn)過(guò)程,因此理解以上邏輯對(duì)于深入掌握自定義視圖狀態(tài)管理機(jī)制具有舉足輕重的作用。
2、實(shí)現(xiàn)基于Control基類的自定義視圖狀態(tài)管理
如果開(kāi)發(fā)人員需要優(yōu)化默認(rèn)視圖狀態(tài)管理機(jī)制,以提高控件運(yùn)行效率和性能,那么必須理解Control基類中默認(rèn)視圖狀態(tài)管理機(jī)制。通過(guò)掌握這個(gè)管理機(jī)制,可以模仿其處理過(guò)程以實(shí)現(xiàn)自定義視圖狀態(tài)管理。
實(shí)現(xiàn)基于Control基類的自定義視圖狀態(tài)管理,需要開(kāi)發(fā)人員實(shí)現(xiàn)3個(gè)方法:LoadViewState、SaveViewState和TrackViewState。它們與上一小節(jié)中介紹的IStateManager接口成員方法同名,并且在方法意義上也基本相同。在此就不對(duì)這3個(gè)方法多做說(shuō)明了。
Control基類中的默認(rèn)視圖狀態(tài)管理機(jī)制定義了一個(gè)StateBag類型的ViewState屬性,并將視圖狀態(tài)管理的任務(wù)委托給它。下面請(qǐng)看Control基類的默認(rèn)狀態(tài)管理的實(shí)現(xiàn)邏輯。
protected virtual StateBag ViewState{
get {
if(_viewState != null)
{
return _viewState;
}
_viewState = new StateBag(ViewStateIgnoresCase);
if(IsTrackingViewState)
_viewState.TrackViewState();
return _viewState;
}
}
protected virtual void TrackViewState(){
if(_viewState != null) {
_viewState.TrackViewState();
}
return null;
}
protected virtual object SaveViewState(){
if(_viewState != null) {
_viewState.SaveViewState();
}
return null;
}
protected virtual void LoadViewState(object savedState){
if(savedState != null) {
ViewState.LoadViewState(savedState);
}
}
從上面的代碼可以看出:ViewState屬性是StateBag類型,當(dāng)_viewState不為null時(shí),則返回_viewState;當(dāng)_viewState為null時(shí),則初始化一個(gè)StateBag類型的變量_viewState,并判斷控件是否正在跟蹤其視圖狀態(tài)更改,如果服務(wù)器控件正在跟蹤其視圖狀態(tài)更改,那么就調(diào)用TrackViewState方法開(kāi)始狀態(tài)跟蹤,最后返回_viewState。另外,在TrackViewState、SaveViewState、LoadViewState方法中,均使用了StateBag類中有關(guān)視圖狀態(tài)管理的方法。
在Control基類的默認(rèn)視圖狀態(tài)管理過(guò)程中,由于定義了ViewState屬性為StateBag類型,所以必然使用上文中StateBag類實(shí)現(xiàn)視圖狀態(tài)管理的邏輯。如果讓Control基類實(shí)現(xiàn)IStateManager接口中的方法和屬性,那么其實(shí)現(xiàn)過(guò)程必然與StateBag類實(shí)現(xiàn)IStateManager接口大同小異,這必然將造成重復(fù),由此可能造成.NET框架改變IStateManager接口的訪問(wèn)性質(zhì)。此外,在進(jìn)行自定義視圖狀態(tài)管理的過(guò)程中,可能出現(xiàn)StateBag類型與Control基類的視圖狀態(tài)管理機(jī)制的沖突,那樣就可能產(chǎn)生混亂。而采用目前的這種方式,無(wú)論從靈活性、繼承性、可復(fù)用性,以致從編程人員的習(xí)慣上,都具有很多優(yōu)點(diǎn)。
自定義控件狀態(tài)管理
視圖狀態(tài)與控件狀態(tài)在數(shù)據(jù)管理方面不太相同。ASP.NET 2.0在支持針對(duì)簡(jiǎn)單屬性的默認(rèn)視圖狀態(tài)管理機(jī)制的同時(shí),還支持自定義視圖狀態(tài)管理。然而,對(duì)于控件狀態(tài)管理而言,則不存在默認(rèn)控件狀態(tài)管理機(jī)制。開(kāi)發(fā)人員必須實(shí)現(xiàn)自定義控件狀態(tài)管理過(guò)程。本小節(jié)介紹一下自定義控件狀態(tài)管理的實(shí)現(xiàn)方法,這對(duì)于實(shí)現(xiàn)基于控件狀態(tài)功能的對(duì)象有著重要意義。
實(shí)際上,在前面系列文章介紹控件狀態(tài)的過(guò)程中,讀者已經(jīng)接觸了控件狀態(tài)實(shí)現(xiàn)的內(nèi)容,其中就包括自定義控件狀態(tài)管理的實(shí)現(xiàn)。這個(gè)過(guò)程的實(shí)現(xiàn)與基于Control基類的自定義視圖狀態(tài)管理非常相似,二者都需要重寫(xiě)Control基類中的方法。實(shí)現(xiàn)自定義控件狀態(tài)管理需要重寫(xiě)Control基類的SaveControlState和LoadControlState。下面列舉了一段簡(jiǎn)單示例代碼。
private int currentIndex = 0;
protected override void OnInit(EventArgs e) {
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override object SaveControlState() {
return currentIndex != 0 ? (object)currentIndex : null;
}
protected override void LoadControlState(object state) {
if (state != null) { currentIndex = (int)state; }
}
}
實(shí)現(xiàn)自定義控件狀態(tài)管理分為3個(gè)關(guān)鍵步驟:
(1)調(diào)用RegisterRequiresControlState方法。該方法用于將自定義控件注冊(cè)為具有持久性控件狀態(tài)的控件。
?。?)重寫(xiě)SaveControlState方法。該方法用于保存自頁(yè)回發(fā)到服務(wù)器后發(fā)生的任何服務(wù)器控件狀態(tài)更改。
?。?)重寫(xiě)LoadControlState方法。該方法用于從SaveControlState方法保存的上一個(gè)頁(yè)請(qǐng)求還原控件狀態(tài)信息。
小結(jié)
本章主要介紹了自定義視圖狀態(tài)和控件狀態(tài)管理的內(nèi)容。它們對(duì)于實(shí)現(xiàn)自定義服務(wù)器控件有著重要意義。建議讀者首先深入理解理論知識(shí),然后再嘗試進(jìn)行開(kāi)發(fā)工作,這樣可獲得更好的學(xué)習(xí)效果。