Page对象在LoadState阶段都做了什么?
我们知道,页面的每次回发,都少不了LoadState阶段,在这个阶段,我们调用页面的LoadAllState()方法,下边我们看看这个方法的源码:
1 private void LoadAllState() {
2
3 object state = LoadPageStateFromPersistenceMedium();
4 IDictionary controlStates = null;
5 Pair allSavedViewState = null;
6 Pair statePair = state as Pair;
7 if (state != null) {
8 controlStates = statePair.First as IDictionary;
9 allSavedViewState = statePair.Second as Pair;
10 }
11
12 // The control state (controlStatePair) was saved as an dictionary of objects:
13 // 1. A list of controls that require postback[under the page id]
14 // 2. A dictionary of control states
15
16 if (controlStates != null) {
17 _controlsRequiringPostBack = (ArrayList)controlStates[PageRegisteredControlsThatRequirePostBackKey];
18
19 if (_registeredControlsRequiringControlState != null) {
20 foreach (Control ctl in _registeredControlsRequiringControlState) {
21 ctl.LoadControlStateInternal(controlStates[ctl.UniqueID]);
22 }
23 }
24 }
25
26 // The view state (allSavedViewState) was saved as an array of objects:
27 // 1. The hash code string
28 // 2. The state of the entire control hierarchy
29
30 // Is there any state?
31 if (allSavedViewState != null) {
32 // Get the hash code from the state
33 string hashCode = (string) allSavedViewState.First;
34
35 // If it's different from the current one, the layout has changed
36 int viewhash = Int32.Parse(hashCode, NumberFormatInfo.InvariantInfo);
37 _fPageLayoutChanged = viewhash != GetTypeHashCode();
38
39 // If the page control layout has changed, don't attempt to
40 // load any more state.
41 if (!_fPageLayoutChanged) {
42 // UNCOMMENT FOR DEBUG OUTPUT
43 // WalkViewState(allSavedViewState.Second, null, 0);
44 LoadViewStateRecursive(allSavedViewState.Second);
45
46 }
47 }
48 }
2
3 object state = LoadPageStateFromPersistenceMedium();
4 IDictionary controlStates = null;
5 Pair allSavedViewState = null;
6 Pair statePair = state as Pair;
7 if (state != null) {
8 controlStates = statePair.First as IDictionary;
9 allSavedViewState = statePair.Second as Pair;
10 }
11
12 // The control state (controlStatePair) was saved as an dictionary of objects:
13 // 1. A list of controls that require postback[under the page id]
14 // 2. A dictionary of control states
15
16 if (controlStates != null) {
17 _controlsRequiringPostBack = (ArrayList)controlStates[PageRegisteredControlsThatRequirePostBackKey];
18
19 if (_registeredControlsRequiringControlState != null) {
20 foreach (Control ctl in _registeredControlsRequiringControlState) {
21 ctl.LoadControlStateInternal(controlStates[ctl.UniqueID]);
22 }
23 }
24 }
25
26 // The view state (allSavedViewState) was saved as an array of objects:
27 // 1. The hash code string
28 // 2. The state of the entire control hierarchy
29
30 // Is there any state?
31 if (allSavedViewState != null) {
32 // Get the hash code from the state
33 string hashCode = (string) allSavedViewState.First;
34
35 // If it's different from the current one, the layout has changed
36 int viewhash = Int32.Parse(hashCode, NumberFormatInfo.InvariantInfo);
37 _fPageLayoutChanged = viewhash != GetTypeHashCode();
38
39 // If the page control layout has changed, don't attempt to
40 // load any more state.
41 if (!_fPageLayoutChanged) {
42 // UNCOMMENT FOR DEBUG OUTPUT
43 // WalkViewState(allSavedViewState.Second, null, 0);
44 LoadViewStateRecursive(allSavedViewState.Second);
45
46 }
47 }
48 }
在这个方法中,第3行,通过LoadPageStateFromPersistenceMedium()方法,得到一个Pair对象,Pair.First对应的是控件的ControState,这个我们放到以后再谈,Pair.Second对应控件的视图状态。第44行,调用控件的LoadViewStateRecursive方法,这个方法是递归载入控件视图状态的开始,下边我们列出这个方法的源代码:
1 internal void LoadViewStateRecursive(object savedState) {
2 // nothing to do if we have no state
3 if (savedState == null || flags[disableViewState])
4 return;
5
6 if (Page != null && Page.IsPostBack) {
7 object controlState = null;
8 object adapterState = null;
9 ArrayList childState = null;
10
11 Pair allSavedState = savedState as Pair;
12 if (allSavedState != null) {
13 controlState = allSavedState.First;
14 childState = (ArrayList)allSavedState.Second;
15 }
16 else {
17 Debug.Assert(savedState is Triplet);
18 Triplet t = (Triplet)savedState;
19
20 controlState = t.First;
21 adapterState = t.Second;
22 childState = (ArrayList)t.Third;
23 }
24
25 try {
26 if ((adapterState != null) && (_adapter != null)) {
27 _adapter.LoadAdapterViewState(adapterState);
28 }
29
30 if (controlState != null) {
31 LoadViewState(controlState);
32 }
33
34 if (childState != null) {
35 if (LoadViewStateByID) {
36 LoadChildViewStateByID(childState);
37 }
38 else {
39 LoadChildViewStateByIndex(childState);
40 }
41 }
42 }
43 catch (InvalidCastException) {
44 // catch all viewstate loading problems with casts. They are most likely changed control trees.
45 throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts));
46 }
47 catch (IndexOutOfRangeException) {
48 // catch all viewstate loading problems with indeces. They are most likely changed control trees.
49 throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts));
50 }
51 }
52
53 _controlState = ControlState.ViewStateLoaded;
54 }
2 // nothing to do if we have no state
3 if (savedState == null || flags[disableViewState])
4 return;
5
6 if (Page != null && Page.IsPostBack) {
7 object controlState = null;
8 object adapterState = null;
9 ArrayList childState = null;
10
11 Pair allSavedState = savedState as Pair;
12 if (allSavedState != null) {
13 controlState = allSavedState.First;
14 childState = (ArrayList)allSavedState.Second;
15 }
16 else {
17 Debug.Assert(savedState is Triplet);
18 Triplet t = (Triplet)savedState;
19
20 controlState = t.First;
21 adapterState = t.Second;
22 childState = (ArrayList)t.Third;
23 }
24
25 try {
26 if ((adapterState != null) && (_adapter != null)) {
27 _adapter.LoadAdapterViewState(adapterState);
28 }
29
30 if (controlState != null) {
31 LoadViewState(controlState);
32 }
33
34 if (childState != null) {
35 if (LoadViewStateByID) {
36 LoadChildViewStateByID(childState);
37 }
38 else {
39 LoadChildViewStateByIndex(childState);
40 }
41 }
42 }
43 catch (InvalidCastException) {
44 // catch all viewstate loading problems with casts. They are most likely changed control trees.
45 throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts));
46 }
47 catch (IndexOutOfRangeException) {
48 // catch all viewstate loading problems with indeces. They are most likely changed control trees.
49 throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts));
50 }
51 }
52
53 _controlState = ControlState.ViewStateLoaded;
54 }
在上边的源代码中,第11行,将传入的object对象转换成Pair或Triplet对象,具体转换成什么对象,和Control.SaveViewStateRecursive有直接的关系,对比着SaveViewStateRecursive方法的实现,要理解LoadViewStateRecursive很容易。我们这里暂且也Pair对象为例,我们在代码的30-31行能看到,Pair.First对应当前控件的视图状态,如果这个视图状态不为null,将调用控件的LoadViewState方法。在代码的第34-41行能看到,Pair.Second是当前控件的子控件的视图信息,通过LoadChildViewStateByID方法或LoadChildViewStateByIndex方法,将试图状态传递给子控件。在这两个方法内部,又会调用子控件的LoadViewStateRecursive方法,开始新一轮的循环。我们用下边一段简单的来做一个说明:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Trace="true" EnableViewState="false" %>
<%@ Register Assembly="AspNetPager" Namespace="Wuqi.Webdiyer" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
<asp:Button ID="Button1" runat="server" Text="Button" /></div>
</form>
</body>
</html>
<%@ Register Assembly="AspNetPager" Namespace="Wuqi.Webdiyer" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
<asp:Button ID="Button1" runat="server" Text="Button" /></div>
</form>
</body>
</html>
这段代码在页面的LoadState阶段,Page,HtmlForm,Literal这三个对象对应的顺序图为: