Control.SaveViewState是如何保存视图信息的

我们平时所见到的web服务器控件,一般而言,其直接的基类,不是WebControl就是Control,我们今天说说Control的SaveViewState方法,这个方法的源码如下:

private StateBag _viewState; 

 

 1        // Save modified state the control would like restored on the postback.
 2        // Return null if there is no state to save. 
 3
 4        /**//// <devdoc>
 5        ///    <para>
 6        ///       Saves view state for use with a later <see cref='System.Web.UI.Control.LoadViewState'/> 
 7        ///       request.
 8        ///    </para> 
 9        /// </devdoc> 

10        protected virtual object SaveViewState() {
11            // Save values cached out of view state 
12            if (flags[visibleDirty]) {
13                ViewState["Visible"= !flags[invisible];
14            }

15            if (_viewState != null
16                return _viewState.SaveViewState();
17 
18            return null
19        }

第12行代码判断控件是否可见,第15行代码判断_viewState是否为null,如果在某一个控件中,所有的操作中都没有使用控件本身的ViewState属性,那么_viewState就是null,这种情况一般是不存在的。如果_viewState不为null,由于_viewState对象的类型是StateBag,则调用StataBag.SaveViewState。
 1private IDictionary bag;
 2        /*
 3         * Constructs an StateBag 
 4         */

 5 
 6        /// <devdoc> 
 7        /// <para>Initializes a new instance of the <see cref='System.Web.UI.StateBag'/> class.</para>
 8        /// </devdoc> 

 9        public StateBag() : this(false{
10        }

11
12        /* 
13         * Constructs an StateBag
14         */
 
15 
16        /// <devdoc>
17        /// <para>Initializes a new instance of the <see cref='System.Web.UI.StateBag'/> class that allows stored state 
18        ///    values to be case-insensitive.</para>
19        /// </devdoc>

20        public StateBag(bool ignoreCase) {
21            marked = false
22            this.ignoreCase = ignoreCase;
23            bag = CreateBag(); 
24        }
 
25        private IDictionary CreateBag() {
26            return new HybridDictionary(ignoreCase); 
27        }
 

 1        /*
 2         * Return object containing state that has been modified since "mark".
 3         * Returns null if there is no modified state.
 4         */
 
 5
 6        /// <devdoc> 
 7        ///    <para>Returns an object that contains all state changes for items stored in the 
 8        ///    <see langword='StateBag'/> object.</para>
 9        /// </devdoc> 

10        internal object SaveViewState() {
11            ArrayList data = null;
12
13            // 
14
15            if (bag.Count != 0
16                IDictionaryEnumerator e = bag.GetEnumerator(); 
17                while (e.MoveNext()) {
18                    StateItem item = (StateItem)(e.Value); 
19                    if (item.IsDirty) {
20                        if (data == null{
21                            data = new ArrayList();
22                        }
 
23#if OBJECTSTATEFORMATTER
24                        data.Add(new IndexedString((string)e.Key)); 
25#else 
26                        data.Add(e.Key);
27#endif 
28                        data.Add(item.Value);
29                    }

30                }

31            }
 
32
33            return data; 
34        }

通过上边的代码可以看出,SateBag.SaveViewState方法中的bag是HybridDictionary类型的实例,HybridDictionary类型实现了 IEnumerable接口,我们可以使用循环算法,依次取出其中的元素,如果有如何条件的元素,他们将会被保存在data对象里边,然后返回data对象。至此,控件的ViewState保存完毕。
这里边有一个关键的地方,那就是StateBag的IsDirty属性。

IsDirty属性和我们平时使用的ViewState有什么关系呢?默认情况下,IsDirty属性为false,它是怎么变成true的呢?要理解这些,请看下边的代码:

    void Page_Load(Object sender, EventArgs e)
    
{
        
this.Literal1.Text = "Hello World!";
    }
Literal.Text源码
 1        /**//// <devdoc> 
 2        ///     [To be supplied.]
 3        /// </devdoc>

 4        [
 5        Localizable(true), 
 6        Bindable(true),
 7        WebCategory("Appearance"), 
 8        DefaultValue(""), 
 9        WebSysDescription(SR.Literal_Text),
10        ] 
11        public string Text {
12            get {
13                string s = (string)ViewState["Text"];
14                return (s != null? s : String.Empty; 
15            }

16            set 
17                ViewState["Text"= value; 
18            }

19        }
 

从上边两段代码可以看出,我们用上边的代码对Literal控件的Text属性赋值,相当于ViewState["Text"] = "Hello World!";,我们前边已经分析过,ViewState属性是StateBag类型的对象,StateBag的this属性源码为:

 1Code
 2        /**//// <devdoc> 
 3        ///    <para> Indicates the value of an item stored in the
 4        ///    <see langword='StateBag'/> 
 5        ///    object. Setting this property with a key not already stored in the StateBag will
 6        ///    add an item to the bag. If you set this property to <see langword='null'/> before
 7        ///    the TrackState method is called on an item will remove it from the bag. Otherwise,
 8        ///    when you set this property to <see langword='null'/> 
 9        ///    the key will be saved to allow tracking of the item's state.</para>
10        /// </devdoc> 

11        public object this[string key] 
12            get {
13                if (String.IsNullOrEmpty(key)) 
14                    throw ExceptionUtil.ParameterNullOrEmpty("key");
15
16                StateItem item = bag[key] as StateItem;
17                if (item != null
18                    return item.Value;
19                return null
20            }
 
21            set {
22                Add(key,value); 
23            }

24        }
StateBag.Add方法源码:
 1Code
 2        /**//* 
 3         * Add a new StateItem or update an existing StateItem in the bag.
 4         */

 5
 6        /**//// <devdoc> 
 7        ///    <para>[To be supplied.]</para>
 8        /// </devdoc> 

 9        public StateItem Add(string key,object value) 
10
11            if (String.IsNullOrEmpty(key)) 
12                throw ExceptionUtil.ParameterNullOrEmpty("key");
13
14            StateItem item = bag[key] as StateItem;
15 
16            if (item == null{
17                if (value != null || marked) 
18                    item = new StateItem(value); 
19                    bag.Add(key,item);
20                }
 
21            }

22            else {
23                if (value == null && !marked) {
24                    bag.Remove(key); 
25                }

26                else 
27                    item.Value = value; 
28                }

29            }
 
30            if (item != null && marked) {
31                item.IsDirty = true;
32            }

33            return item; 
34        }

上边两段代码都不复杂,有一个地方需要我们注意,就是StateBag的Add方法,我们可以看到if(item != null && marked)条件成立的话,这个item的IsDirty属性就被赋值为true,item不为null这个好理解,marked是怎么成为true的呢,默认情况下,这个字段的值是false。
要理解这点,就要从页面的生命周期开始说起,页面在"Begin Init"阶段,调用Control.InitRecursive(null)方法,在这个方法的内部,调用Control.TrackViewState()方法,下边列出Control.TrackViewState()方法的源码:

        /// <devdoc>
        
///    <para>Turns on tracking of view state changes to the control 
        
///       so that they can be stored in the <see langword='StateBag'/>
        
///       object.</para> 
        
/// </devdoc> 

        protected virtual void TrackViewState() {
            
if (_viewState != null
                _viewState.TrackViewState();

            flags.Set(marked);
        }
 
StateBag.TrackViewState()源码:

从上边两段代码,可以看出,我们前边提到的marked字段,在这个方法中被赋值为true了。
posted @ 2008-04-09 17:00  王庆  阅读(840)  评论(0编辑  收藏  举报