2、視圖的載入
圖2
2所示在載入視圖的時候會調用LoadAllState函數:
代碼
private void LoadAllState()
{
object obj2 = this.LoadPageStateFromPersistenceMedium();
IDictionary first = null;
Pair second = null;
Pair pair2 = obj2 as Pair;
if (obj2 != null)
{
first = pair2.First as IDictionary;
second = pair2.Second as Pair;
}
if (first != null)
{
this._controlsRequiringPostBack = (ArrayList) first["__ControlsRequirePostBackKey__"];
if (this._registeredControlsRequiringControlState != null)
{
foreach (Control control in (IEnumerable) this._registeredControlsRequiringControlState)
{
control.LoadControlStateInternal(first[control.UniqueID]);
}
}
}
if (second != null)
{
string s = (string) second.First;
int num = int.Parse(s, NumberFormatInfo.InvariantInfo);
this._fPageLayoutChanged = num != this.GetTypeHashCode();
if (!this._fPageLayoutChanged)
{
base.LoadViewStateRecursive(second.Second);
}
}
}
在LoadAllState中最先調用的是object obj2 = this.LoadPageStateFromPersistenceMedium()其中LoadPageStateFromPersistenceMedium實際上返回的是一個Pair對象(請對比視圖儲存中的SavePageStateToPersistenceMedium傳入的參數也是個Pair)
深入LoadPageStateFromPersistenceMedium:
protected internal virtual object LoadPageStateFromPersistenceMedium()
{
PageStatePersister pageStatePersister = this.PageStatePersister;
try
{
pageStatePersister.Load();
}
catch (HttpException exception)
{
if (this._pageFlags[8])
{
return null;
}
exception.WebEventCode = 0xbba;
throw;
}
return new Pair(pageStatePersister.ControlState, pageStatePersister.ViewState);
}
這個函數其實就是構造了個PageStatePersister對象pageStatePersister,然後用pageStatePersister.Load()將回傳頁面上的input資訊進行讀取並且還原序列化還原成pageStatePersister.ControlState和pageStatePersister.ViewState,最後利用還原的值返回個Pair對象
回到LoadAllState:
IDictionary first = null;
Pair second = null;
Pair pair2 = obj2 as Pair;
if (obj2 != null)
{
first = pair2.First as IDictionary;
second = pair2.Second as Pair;
}
這幾句就是將LoadPageStateFromPersistenceMedium返回的Pair對象進行拆分,將First還原成IDictionary散列集合這就是頁面所有的控制項狀態,然後將Second還原成個Pair,這個Pair就包含了頁面控制項樹的視圖資訊,其實這裡就是將SaveAllState裡用控制項狀態和控制項視圖構造的Pair對象state又拆分並還原了。
if (first != null)
{
this._controlsRequiringPostBack = (ArrayList) first["__ControlsRequirePostBackKey__"];
if (this._registeredControlsRequiringControlState != null)
{
foreach (Control control in (IEnumerable) this._registeredControlsRequiringControlState)
{
control.LoadControlStateInternal(first[control.UniqueID]);
}
}
}
這幾句是對頁面上所有註冊要使用控制項狀態的控制項進行遍曆,並依次用控制項的唯一ID在first 散列集合裡找到控制項對應的控制項狀態資訊(散列集合的每個都是Pair對象,如果不清楚請參考視圖儲存的SaveAllState邏輯)並調用LoadControlStateInternal
internal void LoadControlStateInternal(object savedStateObj)
{
if (!this.flags[0x100000])
{
this.flags.Set(0x100000);
Pair pair = (Pair) savedStateObj;
if (pair != null)
{
Page page = this.Page;
if ((page == null) || page.ShouldLoadControlState(this))
{
if (pair.First != null)
{
this.LoadControlState(pair.First);
}
if ((this._adapter != null) && (pair.Second != null))
{
this._adapter.LoadAdapterControlState(pair.Second);
}
}
}
}
}
LoadControlStateInternal中首先將傳入的參數轉換為了Pair對象,然後對pair.First調用LoadControlState讀取本控制項的控制項狀態(和SaveControlState一樣這是個虛擬空函數要自己實現邏輯),this._adapter != null如果適配器不為空白,對pair.Second調用LoadAdapterControlState從適配器的角度載入本控制項的控制項狀態,LoadAdapterControlState是一個虛擬空函數,如果為控制項指定了適配器,也要實現適配器控制項狀態載入邏輯,可見LoadControlStateInternal為SaveControlStateInternal的逆過程——載入控制項狀態。
回到LoadAllState
if (second != null)
{
string s = (string) second.First;
int num = int.Parse(s, NumberFormatInfo.InvariantInfo);
this._fPageLayoutChanged = num != this.GetTypeHashCode();
if (!this._fPageLayoutChanged)
{
base.LoadViewStateRecursive(second.Second);
}
}
前面說了LoadPageStateFromPersistenceMedium返回的Pair的Second是控制項的視圖,所以上面這幾句的核心就是base.LoadViewStateRecursive(second.Second)對pair.Second.Second遞迴讀取控制項樹的視圖資訊,請看LoadViewStateRecursive:
internal void LoadViewStateRecursive(object savedState)
{
if ((savedState != null) && !this.flags[4])
{
if ((this.Page != null) && this.Page.IsPostBack)
{
object first = null;
object state = null;
ArrayList childState = null;
Pair pair = savedState as Pair;
if (pair != null)
{
first = pair.First;
childState = (ArrayList) pair.Second;
}
else
{
Triplet triplet = (Triplet) savedState;
first = triplet.First;
state = triplet.Second;
childState = (ArrayList) triplet.Third;
}
try
{
if ((state != null) && (this._adapter != null))
{
this._adapter.LoadAdapterViewState(state);
}
if (first != null)
{
this.LoadViewState(first);
}
if (childState != null)
{
if (this.LoadViewStateByID)
{
this.LoadChildViewStateByID(childState);
}
else
{
this.LoadChildViewStateByIndex(childState);
}
}
}
catch (InvalidCastException)
{
throw new HttpException(SR.GetString("Controls_Cant_Change_Between_Posts"));
}
catch (IndexOutOfRangeException)
{
throw new HttpException(SR.GetString("Controls_Cant_Change_Between_Posts"));
}
}
this._controlState = ControlState.ViewStateLoaded;
}
}
首先
object first = null;
object state = null;
ArrayList childState = null;
Pair pair = savedState as Pair;
if (pair != null)
{
first = pair.First;
childState = (ArrayList) pair.Second;
}
else
{
Triplet triplet = (Triplet) savedState;
first = triplet.First;
state = triplet.Second;
childState = (ArrayList) triplet.Third;
}
這是根據傳入LoadViewStateRecursive的參數值savedState 判斷其是Pair還是Triplet ,並根據相應的情況還原為first本控制項的視圖,state適配器的視圖,childState子控制項視圖的散列集合(對比SaveViewStateRecursive中相應的逆過程來理解)
接著
if ((state != null) && (this._adapter != null))
{
this._adapter.LoadAdapterViewState(state);
}
if (first != null)
{
this.LoadViewState(first);
}
if ((state != null) && (this._adapter != null))表示如果還原的適配器視圖資訊不為空白且控制項的適配器也不為空白,那麼就用this._adapter.LoadAdapterViewState(state)從適配器角度讀取控制項的視圖資訊(LoadAdapterViewState是虛擬空函數邏輯要自己實現),然後this.LoadViewState(first)通過LoadViewState載入first視圖資訊到本控制項:
protected virtual void LoadViewState(object savedState)
{
if (savedState != null)
{
this.ViewState.LoadViewState(savedState);
object obj2 = this.ViewState["Visible"];
if (obj2 != null)
{
if (!((bool) obj2))
{
this.flags.Set(0x10);
}
else
{
this.flags.Clear(0x10);
}
this.flags.Set(0x20);
}
}
}
可見LoadViewState的核心就是this.ViewState.LoadViewState(savedState)載入本控制項的ViewState集合,當然根據試圖的儲存所講SaveViewState返回一個ArrayList那麼這裡傳入的savedState也應該是個ArrayList
回到LoadViewStateRecursive
if (childState != null)
{
if (this.LoadViewStateByID)
{
this.LoadChildViewStateByID(childState);
}
else
{
this.LoadChildViewStateByIndex(childState);
}
}
這幾句就是根據實際情況根據子控制項ID載入視圖資訊或根據子控制項在控制項樹中的序列載入視圖資訊
internal void LoadChildViewStateByID(ArrayList childState)
{
int count = childState.Count;
for (int i = 0; i < count; i += 2)
{
string id = (string) childState[i];
object savedState = childState[i + 1];
Control control = this.FindControl(id);
if (control != null)
{
control.LoadViewStateRecursive(savedState);
}
else
{
this.EnsureOccasionalFields();
if (this._occasionalFields.ControlsViewState == null)
{
this._occasionalFields.ControlsViewState = new Hashtable();
}
this._occasionalFields.ControlsViewState[id] = savedState;
}
}
}
internal void LoadChildViewStateByIndex(ArrayList childState)
{
ControlCollection controls = this.Controls;
int count = controls.Count;
int num2 = childState.Count;
for (int i = 0; i < num2; i += 2)
{
int num4 = (int) childState[i];
object savedState = childState[i + 1];
if (num4 < count)
{
controls[num4].LoadViewStateRecursive(savedState);
}
else
{
this.EnsureOccasionalFields();
if (this._occasionalFields.ControlsViewState == null)
{
this._occasionalFields.ControlsViewState = new Hashtable();
}
this._occasionalFields.ControlsViewState[num4] = savedState;
}
}
}
前面在視圖的儲存講到數組列表中控制項的視圖和控制項本身是一對一對存在的,所以不管是LoadChildViewStateByID或LoadChildViewStateByIndex從數組中閱讀檢視資訊也是一對一對的在讀取,然後根據讀取的資料找到相應的控制項並對其視圖資訊savedState(是個Pair或Triplet)調用LoadViewStateRecursive遞迴載入子控制項的視圖。
這樣在LoadAllState中通過調用迴圈調用LoadControlStateInternal和遞迴調用LoadViewStateRecursive就將頁面所有控制項的檢視狀態和所有控制項的視圖資訊載入完畢了
可見視圖的載入就是視圖儲存的的逆過程,你會發現在載入過程的每一步都可以在儲存過程中找到相應的步驟與其對應,所以要通過比較來理解兩個過程。