程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> ViewState機制由淺入深2

ViewState機制由淺入深2

編輯:關於.NET

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)   LoadViewStateRecursiveLoadViewStateRecursive的聲明如下: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)   SaveViewStateRecursiveSaveViewStateRecursive的聲明如下:

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();
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved