视图状态默认支持很多类型的数据存储,其中基本类型的有字符串、数字、布尔值、颜色、日期、字节,以及各种类型的数组等。以下是一个最常见的典型用法:

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作为基类实现自定义类型视图状态的示例。