• ViewState机制由浅入深2


     

    2.2.2   Pair类及ViewState的存储

    Page及所有控件的ViewState、ControlState都是存储在Pair类的实例中,了解Pair类及ViewState如何存储在Pair类中很重要。Pair定义的System.Web.UI中具体定义如下:

    public sealed class Pair

    {

        public object First;

        public object Second;

        public Pair();

        public Pair(object x, object y);

    }

    可以看出Pair类是用作存储两个相关对象的基本结构。Pair是一个工具类,使用它很容易形成一个树的数据结构。将__VIEWSTATE反序列化后就是一个Pair对象。这个对象即保存了控件之间的父子关系,也保存了ViewState信息。ViewState中的Key/Value对被转换为一个ArrayList对象保存在Pair对象中。下面我们来看看它是如何存储的。


    图3

    图3是对Pair的一种图式表示方式,左边表示First对象,右边表示Second对象,根据这种图式方式,图4是利用Pair对象存储ViewState的结构,对于ControlState没有进行具体的展开。从savedState(Pair)开始采用了递归的存储方式,将所有控件的ViewState及关系存储起来,在Pair对象的First中存储ViewState数据,在Second中存储子控件的信息。

    图4

    2.2.3   Control中的处理

    Page类继承自Control类,在实现ViewState机制的时候Page类中主要是涉及序列化和反序列化的工作,ViewState的保存、装载等功能都在Control类中实现由Page类来继承,控件也都继承自Control类,下面对Control类中和ViewState机制相关的属性、方法进行介绍。
    1)     ViewState属性
    ViewState是Page及控件的一个属性,这个属性并不是在Page或控件中定义,它定义在System.Web.UI.Control类中。它的声明如下:

    protected virtual StateBag ViewState{get}

    由于所有服务器端的控件,用户自定义控件,及Page类都是继承自Control类,所以它们都会都具有一个protected的ViewState属性。这个ViewState属性在ViewState机制中很重要,它用来存储控件需要记忆的一些数据。这些数据主要有两类,一类是需要记忆的控件的属性。另外一类是我们想利用ViewState机制来记住的一些数据,比如我们在Web窗体中写如下的代码:

        protected void Page_Load(object sender, EventArgs e)

        {

            if (!this.IsPostBack)

            {

                this.ViewState["Test"] = 0;

            }

            else

            {

                this.ViewState["Test"]=int.Parse(this.ViewState["Test"].ToString()) + 1;

            }

        }
    因为我们创建的Web窗体都是继承自Page类,所以在Web窗体中能否访问Page类的protected的ViewState属性。我们可以通过ViewState属性利用ViewState机制,让它帮助我们记住一些信息。
    ViewState属性的主要作用还是用来记住一些控件的属性值。ViewState属性和控件的其他属性有什么样的联系,才能够利用ViewState属性来记住他们呢?下面用Button类的Text属性举例来说明,Text属性和ViewState属性是什么关系。Button.Text的定义如下:

    public string Text

    {

        get

        {

            string str = (string) this.ViewState["Text"];

            if (str != null)

            {

                return str;

            }

            return string.Empty;

        }

        set

        {

            this.ViewState["Text"] = value;

        }

    }

    通过上面的代码我们可以看出Button.Text属性的值实际上和ViewState中Key为“Text”的Value是关联的。当然Button类的其他属性也是类似的方式,只是对应ViewState中Key不同而已。这样只要ViewState的值能够被记忆,那么Button类的属性也就能够被记忆住了。记忆ViewState的方法就是在Page. SaveAllState中将所有控件的ViewState属性生成一个对象(这是一个特殊的对象,它是一个树状态的存储了所有控件的ViewState属性),然后将这个对象序列化为字符串,发送到客户端。在下次请求的时候,将这个字符串发送给服务器,在Page.LoadAllState中将这个字符串反序列化为一个对象,将这个对象中存储的各个控件的ViewState属性,加载给各个控件的ViewState属性。当我们访问控件的属性的时候就实现了对控件属性的记忆,之前设置的控件属性没有丢失。
    2)     LoadViewStateByID属性

    LoadViewStateByID的声明如下:

    protected bool LoadViewStateByID{get}

    LoadViewStateByID获取一个值,该值指示控件是否通过ID方式加载其视图状态。默认情况下是通过索引方式加载视图状态,索引方式是依赖子控件在父控件的Controls集合中位置。ID方式会根据ID查找控件,效率比较低些,但是有些情形必须使用这种方式比如延迟创建子控件时。

    3)     EnableViewState属性
    EnableViewState是一个bool类型的属性,来决定当前控件的ViewState机制是否可用。其声明如下:

    public virtual bool EnableViewState{get,set}

    4)     LoadViewStateRecursive
    LoadViewStateRecursive的声明如下:
    internalvoid LoadViewStateRecursive(object savedState)
    Page.LoadAllState中调用Control.LoadViewStateRecursive,传入的参数savedState是一个Pair类型的对象,Pair.Fisrt中保存当前控件的ViewState,Pair.Second中保存子控件的ViewState。对于EnableViewState为true时,先通过调用Control.LoadViewState(savedState.First)装载当前控件的ViewState。之后根据LoadViewStateByID属性,装载子控件的ViewState。如果LoadViewStateByID属性为true调用Control.LoadChildViewStateByID(savedState.Second),否则调用
    Control.LoadChildViewStateByIndex(savedState.Second)。savedState.Second是一个ArrayList类型的对象。

    Control.LoadViewState的声明如下:

    protected virtual void LoadViewState(object savedState)
    在Control.LoadViewState中并没有自己实现装载当前控件的ViewState,而是通过ViewState.LoadViewState(savedState)来实现,下面会介绍StateBag的LoadViewState方法。
    LoadChildViewStateByID的声明如下:
    internal void LoadChildViewStateByID(ArrayList childState)
    参数childState是ArrayList类型,childState中存储了当前控件的所有子控件的信息。它的格式是首先是一个控件的ID,其后是这个控件的Pair对象。对childState进行循环,循环中取得控件的ID,根据ID找到控件调用这个控件的LoadViewStateRecursive方法。示意代码如下:

    for (int i = 0; i < count; i += 2)

        {

            string id = (string) childState[i];

            object savedState = childState[i + 1];

           Control control = this.FindControl(id);

            control.LoadViewStateRecursive(savedState);

        }

    LoadChildViewStateByIndex的声明如下:

    internal void LoadChildViewStateByIndex(ArrayList childState)

    childState的存储格式是首先是一个控件的索引,其后是这个控件的Pair对象。根据索引访问访问这个控件,调用其LoadViewStateRecursive方法,示例代码如下:

        for (int i = 0; i < num2; i += 2)

        {

            int num4 = (int) childState[i];

            object savedState = childState[i + 1];

            controls[num4].LoadViewStateRecursive(savedState);

         }

    5)     LoadViewState

    LoadViewState中直接调用ViewState的LoadViewState方法进行ViewState的装载,示意代码如下:

    this.ViewState.LoadViewState(savedState);

    6)     SaveViewStateRecursive
    SaveViewStateRecursive的声明如下:

    internal object SaveViewStateRecursive()

    对于EnableViewState为true时,先调用Control.SaveViewState返回一个包含当前控件的ViewState信息的ArrayList类型对象x。之后对子控件进行递归处理获得一个ArrayList类型的对象z。它的格式是ID(String),savedState(Pair)或者Index(int)savedState(Pair)。最后创建一个Pair对象Pair(x, z)。示意代码如下:

    object x = this.SaveViewState();

    ArrayList z = null;

    ControlCollection controls = this._occasionalFields.Controls;

    int count = controls.Count;

    bool loadViewStateByID = this.LoadViewStateByID;

    for (int i = 0; i < count; i++)

    {

              Control control = controls[i];

              object obj4 = control.SaveViewStateRecursive();

              if (loadViewStateByID)

                        z.Add(control.ID);

              else

                                  z.Add(i);

              z.Add(obj4);

    }

    return new Pair(x, z);

    7)     SaveViewState

    SaveViewState中直接调用ViewState的SaveViewState方法进行ViewState的保存,示意代码如下:

    return this.ViewState.SaveViewState();

    8)     TrackViewState

    在Control.InitRecursive中会调用Control.TrackViewState,因为Control.InitRecursive是被递归调用的,所以每个控件的TrackViewState都会在初始化阶段被调用到。Control.TrackViewState中之间调用ViewState的TrackViewState方法,示意代码如下:

    this.ViewState.TrackViewState();


  • 相关阅读:
    UVa 11090
    针对于取数字型的01背包与完全背包的一点想法
    T^T online judge 1372其实这题题目这么短就是为了让你AK
    AcWing 275. 传纸条
    AcWing274.移动服务
    AcWing273.分级
    第四集,我猜题意老牛逼(划掉)了
    linux环境下c++实现FILETOOLS
    FIFO算法,LRU算法,OPT算法,LFU算法的C++实现
    vscode 通过 coderunner 配置C++ 编译环境 (更新版 2019/6/7)
  • 原文地址:https://www.cnblogs.com/hobe/p/1122213.html
Copyright © 2020-2023  润新知