在前面的系列文章中,我們曾經介紹了檢視狀態和控制項狀態的基本概念和典型應用,從中可以發現,檢視狀態和控制項狀態對於自訂伺服器控制項實現的重要性。本文將繼續這一主題,重點介紹實現檢視狀態和控制項狀態自訂管理的方法。
自訂檢視狀態管理
在介紹檢視狀態時,我們曾經提到過:對於簡單屬性,例如,String、Int等類型,.NET執行引擎將自動啟用預設檢視狀態管理機制,以便完成相應的功能。然而,如果開發人員在ViewState中儲存的是自訂資料類型,或者需要實現自訂方式最佳化檢視狀態管理時,則必須實現自訂檢視狀態管理。
實現自訂檢視狀態管理可以通過兩種方法。方法一:實現System.Web.UI命名空間中的IStateManager介面成員,其中包括IsTrackingViewState屬性和TrackViewState、SaveViewState和LoadViewState方法。這種方法主要是針對自訂資料類型的檢視狀態管理的情況。方法二:重寫Control基類的3個檢視狀態管理方法:TrackViewState、SaveViewState和LoadViewState。這些方法與IStateManager介面定義的3個方法名稱一致。這種方法主要用於通過自訂方式最佳化預設檢視狀態管理的情況,其主要目的在於提高效率和效能。掌握以上兩種實現方法的捷徑是,必須深刻理解.NET架構內部實現檢視狀態管理的過程。下面兩小節內容都是有關內部實現方法的介紹。每一節中均有實現代碼,實際就相當於執行個體代碼。所有伺服器控制項的自訂檢視狀態管理的實現都不會偏離那些代碼所表達的邏輯。當讀者真正掌握了那些內部實現方法,那麼自訂檢視狀態管理的實現方法也就迎刃而解了。
1、實現基於IStateManager介面的自訂檢視狀態管理
對於複雜屬性而言,多數需要實現自訂檢視狀態管理,其關鍵是實現System.Web.UI.IStateManager介面中定義的方法和屬性。下面列舉了IStateManager介面定義代碼。
public interface IStateManager{ bool IsTrackingViewState {get;} void LoadViewState(object state); object SaveViewState(); void TrackViewState();}
如上代碼所示,IStateManager介面要求類實現IsTrackingViewState屬性,以及LoadViewState、SaveViewState和TrackViewState方法。IsTrackingViewState屬性定義,當由類實現時,擷取一個布爾值,通過該值指示伺服器控制項是否正在跟蹤其檢視狀態更改。如果伺服器控制項正在跟蹤其檢視狀態更改,則為true;否則為false。SaveViewState方法定義,當由類實現時,將伺服器控制項的檢視狀態更改儲存到Object中。LoadViewState方法定義,當由類實現時,載入伺服器控制項以前儲存的控制項檢視狀態,其中的參數state表示包含控制項儲存的檢視狀態值的Object。TrackViewState方法定義,當由類實現時,指示伺服器控制項跟蹤其檢視狀態更改。
ViewState屬性與IStateManager介面之間存在密切聯絡。ViewState屬性的類型是StateBag類,StateBag類通過實現IStateManager介面中定義的方法和屬性來參與狀態管理。其實現過程如下。
public sealed class StateBag : IStateManager, IDictionary,ICollection, IEnumerable{
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];
}
}
}
}
}
}
請讀者注意:以上代碼為示意性代碼,並非嚴格意義上的實現代碼。在此列出,主要是用於說明StateBag類實現IStateManager介面的邏輯過程。
通過上面的代碼,我們可以看到:
(1)在IsTrackingViewState屬性中,將該屬性設定為唯讀,並且使用私人變數_isTrackingViewState。
(2)在TrackViewState方法中,把IsTrackingViewState屬性使用的私人變數_isTrackingViewState設定為true,這指示系統當某個StateItem添加到StateBag中,或者某個StateItem值被修改時,StateBag類就會自動將該StateItem標記為修改過即添加dirty標記。
(3)在SaveViewState方法中,迴圈StateBag中的每個StateItem,如果該StateItem被標記為dirty,那麼就將其鍵和值分別添加到兩個ArrayList中,並返回該對象。
(4)在LoadViewState方法中,執行了與SaveViewState方法相反的操作。首先將savedState對象分解為兩個儲存有鍵和值的ArrayList,然後將其中的值載入到相應的StateItem對象中。
以上就是ViewState屬性實現IStateManager介面的基本過程。所有的檢視狀態管理過程,都要使用以上的實現過程,因此理解以上邏輯對於深入掌握自訂檢視狀態管理機制具有舉足輕重的作用。