视图状态默认支持很多类型的数据存储,其中基本类型的有字符串、数字、布尔值、颜色、日期、字节,以及各种类型的数组等。以下是一个最常见的典型用法:
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
在上面代码中有个ViewState的对象,此对象没有多么深奥,只是基类Control中定义的一个属性。追溯到它的基类定义,代码如下:
private StateBag _viewState;
[WebSysDescription("Control_State"), Browsable(false), Designer Serializa
tionVisibility(DesignerSerializationVisibility.Hidden)]
protected virtual StateBag ViewState
{
get
{
if (this._viewState == null)
{
this._viewState = new StateBag(this.ViewStateIgnoresCase);
if (this.IsTrackingViewState)
{
this._viewState.TrackViewState();
}
}
return this._viewState;
}
}
这是一个标准的自定义类型属性。再仔细看一下,该属性的类型为StateBage类,这才是我们要找的关键类,它的代码结构如下:
/// <summary>
/// 获得本书更多内容,请看:
/// </summary>
public sealed class StateBag : IStateManager, IDictionary, ICollection, IEnumerable
{
// Fields
private IDictionary bag;
private bool ignoreCase;
private bool marked;
// Methods
public StateBag()
: this(false)
{
}
public StateBag(bool ignoreCase)
{
this.marked = false;
this.ignoreCase = ignoreCase;
this.bag = this.CreateBag();
}
public StateItem Add(string key, object value)
{
if (string.IsNullOrEmpty(key))
{
throw ExceptionUtil.ParameterNullOrEmpty("key");
}
StateItem item = this.bag[key] as StateItem;
if (item == null)
{
if ((value != null) || this.marked)
{
item = new StateItem(value);
this.bag.Add(key, item);
}
}
else if ((value == null) && !this.marked)
{
this.bag.Remove(key);
}
else
{
item.Value = value;
}
if ((item != null) && this.marked)
{
item.IsDirty = true;
}
return item;
}
public void Clear()
{
this.bag.Clear();
}
private IDictionary CreateBag()
{
return new HybridDictionary(this.ignoreCase);
}
public IDictionaryEnumerator GetEnumerator()
{
return this.bag.GetEnumerator();
}
public bool IsItemDirty(string key)
{
StateItem item = this.bag[key] as StateItem;
return ((item != null) && item.IsDirty);
}
internal void LoadViewState(object state)
{
if (state != null)
{
ArrayList list = (ArrayList)state;
for (int i = 0; i < list.Count; i += 2)
{
string key = ((IndexedString)list[i]).Value;
object obj2 = list[i + 1];
this.Add(key, obj2);
}
}
}
public void Remove(string key)
{
this.bag.Remove(key);
}
internal object SaveViewState()
{
ArrayList list = null;
if (this.bag.Count != 0)
{
IDictionaryEnumerator enumerator = this.bag.GetEnumerator();
while (enumerator.MoveNext())
{
StateItem item = (StateItem)enumerator.Value;
if (item.IsDirty)
{
if (list == null)
{
list = new ArrayList();
}
list.Add(new IndexedString((string)enumerator.Key));
list.Add(item.Value);
}
}
}
return list;
}
public void SetDirty(bool dirty)
{
if (this.bag.Count != 0)
{
foreach (StateItem item in this.bag.Values)
{
item.IsDirty = dirty;
}
}
}
public void SetItemDirty(string key, bool dirty)
{
StateItem item = this.bag[key] as StateItem;
if (item != null)
{
item.IsDirty = dirty;
}
}
void ICollection.CopyTo(Array array, int index)
{
this.Values.CopyTo(array, index);
}
void IDictionary.Add(object key, object value)
{
this.Add((string)key, value);
}
bool IDictionary.Contains(object key)
{
return this.bag.Contains((string)key);
}
void IDictionary.Remove(object key)
{
this.Remove((string)key);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
internal void TrackViewState()
{
this.marked = true;
}
// Properties
public int Count
{
get
{
return this.bag.Count;
}
}
internal bool IsTrackingViewState
{
get
{
return this.marked;
}
}
public object this[string key]
{
get
{
if (string.IsNullOrEmpty(key))
{
throw ExceptionUtil.ParameterNullOrEmpty("key");
}
StateItem item = this.bag[key] as StateItem;
if (item != null)
{
return item.Value;
}
return null;
}
set
{
this.Add(key, value);
}
}
public ICollection Keys
{
get
{
return this.bag.Keys;
}
}
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return this;
}
}
bool IDictionary.IsFixedSize
{
get
{
return false;
}
}
bool IDictionary.IsReadOnly
{
get
{
return false;
}
}
object IDictionary.this[object key]
{
get
{
return this[(string)key];
}
set
{
this[(string)key] = value;
}
}
bool IStateManager.IsTrackingViewState
{
get
{
return this.IsTrackingViewState;
}
}
public ICollection Values
{
get
{
return this.bag.Values;
}
}
}
该类继承了四个接口:IStateManager,IDictionary,ICollection,IEnumerable。IStateManager即.NET Framework为自定义视图状态管理提供的接口,到这里您应该明白我们直接使用ViewState对象时其实是隐式用到了IStateManager接口,只不过Control类不是继承IStateManager实现的,而是采用关联对象方式把StateBag类的一个实例作为自己的一个属性保持而已。这样从技术角度能够把IStateManager接口的几个方法与Control对控件生命周期支持的几个同名方法区别开来(它们命名是相同的)。另外,这几个方法在使用上也非常简便,直接通过属性的方式使用,否则使用时就要重写基类的方法实现,显得比较笨重且缺乏灵活性。
后面三个接口IDictionary,ICollection,IEnumerable主要为视图对象的存储集合以及对集合的快速检索提供支持。在这里可以看到我们使用的ViewState在服务端也存储在一个标准的IDictionary类型中,如下:
private IDictionary bag;
IDictionary集合采用键(string类型)/值(object类型)的格式存储。除了bag对象,还有两个内部变量:
private bool ignoreCase;
private bool marked;
ignoreCase指定在集合中存储的键是否忽略大小写。marked变量就标记是否启用了跟踪监控的变量,只有当该值为true时,才把值保存到视图集合对象中,否则如果集合中有该对象就移除它。在Add方法的核心代码片段中体现了这一点,代码如下:
/// <summary>
/// 获得本书更多内容,请看:
/// </summary>
public StateItem Add(string key, object value)
{
//… …
StateItem item = this.bag[key] as StateItem;
if (item == null)
{
if ((value != null) || this.marked)
{
item = new StateItem(value);
this.bag.Add(key, item);
}
}
else if ((value == null) && !this.marked)
{
this.bag.Remove(key);
}
else
{
item.Value = value;
}
if ((item != null) && this.marked)
{
item.IsDirty = true;
}
return item;
}
这一段代码比较严谨,除了判断marked是否为true,还判断要增加的对象是否为null如果为null,也不会增加到视图集合列表对象中。另外,在视图集合中,对应的值类型为StateItem,它的代码如下所示:
/// <summary>
/// 获得本书更多内容,请看:
/// </summary>
public sealed class StateItem
{
// Fields
private bool isDirty;
private object value;
// Methods
internal StateItem(object initialValue);
// Properties
public bool IsDirty { get; set; }
public object Value { get; set; }
}
在这里除了定义了存储数据内容的object对象的value属性外,还有一个Dirty属性,该属性值标志当前集合中的一个对象是否是脏数据(即被改动过了),SaveViewState方法只对脏数据进行保存,以便提高性能。SaveViewState的代码片段如下:
/// <summary>
/// 获得本书更多内容,请看:
/// </summary>
internal object SaveViewState()
{
ArrayList list = null;
if (this.bag.Count != 0)
{
IDictionaryEnumerator enumerator = this.bag.GetEnumerator();
while (enumerator.MoveNext())
{
StateItem item = (StateItem)enumerator.Value;
if (item.IsDirty)
{
if (list == null)
{
list = new ArrayList();
}
list.Add(new IndexedString((string)enumerator.Key));
list.Add(item.Value);
}
}
}
return list;
}
代码体中的语句if(item.IsDirty)就是对要保存的序列化对象进行过滤,最终返回的list集合对象中的item的Dirty属性值都为true。
StateBag类的关键点就介绍这些。StateBag是.NETFramework提供的一个比较实用的类,并且它实现了IStateManager,可以作为自定义类型视图、状态的一个典型例子,在实现自己的视图状态类时完全可以参考它。在实际开发时,很多情况下也并非一定要显示继承 IStateManager接口,系统类有些类型继承了IStateManager,比如Style,这样我们可以直接拿来使用,还有它的一些派生类TableItemStyle,TableStyle,PanelStyle 都可以直接在控件开发中使用。后面会介绍一个使用TableItemStyle作为基类实现自定义类型视图状态的示例。