Asp.net 2.0 自定义控件开发专题[详细探讨页面状态(视图状态和控件状态)机制及其使用场景](示例代码下载)...

(一). 概述

最近研究了一下Asp.net页面存储状态机制,看了些资料,进行一下汇总.

Web应用程序是无状态的。每次从服务器请求网页时,都会创建网页类的一个新实例。这通

常意味着在每次往返过程中将会丢失所有与该页面及其控件关联的信息.因此页面要维持上次请求

的页面状态,就需要用某种方式将页面状态保存起来,Asp.net技术是用页面状态(视图状态和控件状

态),以下都简称"页面状态". 其中控件状态为Asp.net2.0的新特性.在有些场合,视图状态和控件状

态是可以通用的,但有此场合考虑到性能及其安全等因素,要选择具体适合此场景的页面状态存储方

式.

下面具体介绍一下页面状态的两种方式优缺点及其使用场景.

1.视图状态.

♦概述:视图状态是ASP.NET页框架用于保存往返过程之间的页和控件值的方法。当呈现页

的HTML形式时,需要在回发过程中保留的页的当前状态和值将被序列化为Base64编码的字符串,

并输出到视图状态的隐藏字段中,即页面中Html源代码中的__VIEWSTATE隐藏字段.可以存储:字符

/整数/布尔值/Array对象/ArrayList对象/哈希表等数据类型.

♦视图状态优点:

1.节省服务端资源:由于视图状态是存放到Hide字段(Html代码结构中)传送到客户端的,因

为不占用服务端资源.

2.使用方便:默认已经开启视图状态(有些场合,如控件没有注册服务端事件或者控件没有

动态属情况可以将视图状态关闭,节省网络流量,提高页面呈现速度).

3.安全方面:视图状态通过散列码校检机制和使用3DES等加密机制来保证数据安全.

4.自定义存储位置:在Load和Save方法中可以自定义其存储位置.

♦视图状态缺点:

1.性能:由于其存储到页面Html代码结构中,因此传输数据量大时,会严重影响性能.

可以用视图状态分块机制,将数据分块存储,设置MaxPageStateFieldLength属性.

2.禁用:如果视图状态被禁用,则无法保存页面状态.

3.安全:虽然已经通过加密,但由于其是呈现到客户端隐藏字段区域,因此容易被篡改.


2.控件状态

♦概述:有时,为了让控件正常工作,您需要按顺序存储控件状态数据。例如,如果编写了一个

自定义控件,其中使用了不同的选项卡来显示不同的信息,如(TabTrip/FormView等控件)

为了让自定义控件按预期的方式工作,该控件需要知道在往返行程之间选择了哪个选项

卡。可以使用ViewState属性来实现这一目的,然而,开发人员可以在页级别关闭视图

状态,从而使控件无法正常工作。为了解决此问题,ASP.NET2.0增加了一项新的存储

功能:控件状态的功能。ControlState属性允许您保持特定于某个控件的属性信息,且不

能像ViewState属性那样被关闭。等一下,下面会有详细的示例演示进行测试这一点.

简单地说,当禁用视图状态时,ControlState能够完成ViewState不能够完成的任务.

♦控件状态优点:

1.节省服务端资源:跟视图状态一样,控件状态存储在隐藏字段中,也不占用服务器

资源.

2.比视图状态更可靠:控件状态功能推出的一重大原因就是,当视图状态被禁用时,

它依然可以有效.(下面会有测试示例).

3.自定义存储位置:在Load和Save方法中可以自定义其存储位置.

♦控件状态缺点:

1.性能:由于其存储到页面Html代码结构中,因此传输数据量大时,会严重影响性能.

2.自定义编程.视图状态可以用System.Web.UI.StateBag类型的ViewState来存储使

用,也可以自定义存储编程.控件状态只能自定义编程.

(二). 示例演示其用法

1) . 视图状态

代码示例使用四种不同的属性类型来演示视图状态的用法. 四种类型分别为:

a. 没有使用视图状态简单string类型属性

b. 使用视图状态的简单string类型属性

c. 自定义复杂类型FaceStyle的存储----存储复杂类FaceStyle内部属性

d. 自定义复杂类型FaceStyle的存储----存储复杂类FaceStyle继承的基类的属性

代码中注释已经比较详细, 贴出代码:

1.自定义主控件测试类 ViewStateTest.cs 代码

1///<summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.****.net/ChengKing
4///</summary>
5///<summary>
6///本示例通过存储四种类型不同的属性来演示视图状态存储机制
7///</summary>
8[ToolboxData("<{0}:ViewStateTestrunat=server></{0}:ViewStateTest>")]
9publicclassViewStateTest:WebControl
10{
11privatestring_text;
12[Bindable(true)]
13[DefaultValue("")]
14[Localizable(true)]
15[Category("测试视图状态")]
16[Description("没有使用视图状态存储")]
17publicstringText_NoViewState
18{
19get
20{
21return_text;
22}
23
24set
25{
26this._text=value;
27}
28}
29
30[Bindable(true)]
31[DefaultValue("")]
32[Localizable(true)]
33[Category("测试视图状态")]
34[Description("使用ViewState属性来存储数据此属性")]
35publicstringText_ViewState
36{
37get
38{
39Strings=(String)ViewState["Text_ViewState"];
40return((s==null)?String.Empty:s);
41
42}
43
44set
45{
46ViewState["Text_ViewState"]=value;
47
48}
49}
50
51privateFaceStyle_faceStyle;
52[PersistenceMode(PersistenceMode.InnerProperty)]
53[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
54[NotifyParentProperty(true)]
55[Category("测试视图状态")]
56[Description("自定义视图状态(实现IStateManager接口)存储此属性")]
57publicFaceStyle皮肤样式_CustomViewState
58{
59get
60{
61if(_faceStyle==null)
62{
63_faceStyle=newFaceStyle();
64}
65
66if(IsTrackingViewState)
67{
68((IStateManager)_faceStyle).TrackViewState();
69}
70
71return_faceStyle;
72}
73}
74
75protectedoverridevoidRenderContents(HtmlTextWriteroutput)
76{
77if(DesignMode)
78{
79output.Write("[自定义视图状态存储示例控件]");
80}
81}
82
83protectedoverridevoidCreateChildControls()
84{
85base.CreateChildControls();
86}
87
88protectedoverridevoidRender(HtmlTextWriterwriter)
89{
90base.Render(writer);
91}
92
93protectedoverrideobjectSaveViewState()
94{
95Pairp=newPair();
96p.First=base.SaveViewState();
97p.Second=((IStateManager)皮肤样式_CustomViewState).SaveViewState();
98for(inti=0;i<2;i++)
99{
100if(p.First!=null||p.Second!=null)
101{
102returnp;
103}
104}
105returnnull;
106}
107
108protectedoverridevoidLoadViewState(objectsavedState)
109{
110if(savedState==null)
111{
112base.LoadViewState(null);
113return;
114}
115else
116{
117Pairp=(Pair)savedState;
118if(p==null)
119{
120thrownewArgumentException("无效的ViewState数据!");
121}
122base.LoadViewState(p.First);
123if(p.Second!=null)
124{
125((IStateManager)皮肤样式_CustomViewState).LoadViewState(p.Second);
126}
127}
128}
129}

2. 自定义复杂类 FaceStyle.cs 代码

1///<summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.****.net/ChengKing
4///</summary>
5///<summary>
6///一个复杂的数据类型类定义
7///</summary>
8publicclassFaceStyle:TableItemStyle,IStateManager
9{
10#region类变量
11
12privatebool_blnOK;
13
14#endregion
15
16#region构造函数
17
18publicFaceStyle()
19{
20_blnOK=false;
21}
22
23#endregion
24
25#region属性
26
27[Browsable(true)]
28[Description("自定义类测试变量")]
29publicboolOK
30{
31get
32{
33return_blnOK;
34}
35set
36{
37_blnOK=value;
38}
39}
40
41
42boolIStateManager.IsTrackingViewState
43{
44get
45{
46returnbase.IsTrackingViewState;
47}
48}
49
50#endregion
51
52#region方法
53
54
55//从当前点开始,此控件具有保存视图状态功能
56voidIStateManager.TrackViewState()
57{
58base.TrackViewState();
59}
60
61
62objectIStateManager.SaveViewState()
63{
64object[]state=newobject[2];
65state[0]=base.SaveViewState();
66
67state[1]=(object)OK;
68
69//状态管理会存储此返回的值;另外此方法返回值还有个用途:创建复合控件时取得各个子控件的视图状态时使用
70returnstate;
71}
72
73
74voidIStateManager.LoadViewState(objectstate)
75{
76if(state==null)
77{
78return;
79}
80object[]myState=(object[])state;
81base.LoadViewState(myState[0]);
82
83OK=(bool)myState[1];
84}
85
86#endregion
87}

3. 测试页面 Default.aspx.cs 代码

1///<summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.****.net/ChengKing
4///</summary>
5publicpartialclass_Default:System.Web.UI.Page
6{
7protectedvoidPage_Load(objectsender,EventArgse)
8{
9//禁用页面视图状态测试
10//Page.EnableViewState=false;
11
12//禁用控件视图状态测试
13//this.ViewStateTest1.EnableViewState=false;
14
15}
16protectedvoidbtnSetProperty_Click(objectsender,EventArgse)
17{
18///设置没有用视图状态存储的属性值
19this.ViewStateTest1.Text_NoViewState="我没有用任何视图状态存储!";
20
21///设置用ViewState存储的属性值
22this.ViewStateTest1.Text_ViewState="我是用ViewState容器存储的!";
23
24//设置用自定义视图状态存储的属性值
25this.ViewStateTest1.皮肤样式_CustomViewState.OK=true;
26this.ViewStateTest1.皮肤样式_CustomViewState.BackColor=System.Drawing.Color.LightPink;
27}
28protectedvoidbtnRefresh_Click(objectsender,EventArgse)
29{
30///<summary>
31///ViewState容器存储测试--测试存储ViewStateTest1.Text_NoViewState属性
32///</summary>
33if(this.ViewStateTest1.Text_NoViewState=="我没有用任何视图状态存储!")
34{
35this.lbDisplay.Text="this.ViewStateTest1.Text_NoViewState属性已经保存了视图状态,:)<br><br>";
36}
37else
38{
39this.lbDisplay.Text="this.ViewStateTest1.Text_NoViewState属性没有保存视图状态,:(<br><br>";
40}
41
42
43///<summary>
44///ViewState容器存储测试--测试存储ViewStateTest1.Text_ViewState属性
45///</summary>
46if(this.ViewStateTest1.Text_ViewState=="我是用ViewState容器存储的!")
47{
48this.lbDisplay.Text+="this.ViewStateTest1.Text_ViewState属性已经保存了视图状态,:)<br><br>";
49}
50else
51{
52this.lbDisplay.Text+="this.ViewStateTest1.Text_ViewState属性没有保存视图状态,:(<br><br>";
53}
54
55
56///<summary>
57///自定义视图状态测试--测试存储类ViewStateTest1.FaceStyle的内部属性OK
58///</summary>
59if(this.ViewStateTest1.皮肤样式_CustomViewState.OK==true)
60{
61this.lbDisplay.Text+="this.ViewStateTest1.皮肤样式_CustomViewState属性.OK已经保存了视图状态,:)<br><br>";
62}
63else
64{
65this.lbDisplay.Text+="this.ViewStateTest1.皮肤样式_CustomViewState属性.OK没有保存视图状态,:(<br><br>";
66}
67
68
69///<summary>
70///自定义视图状态测试--测试存储类ViewStateTest1.FaceStyle的基类TableItemStyle中的属性BackColor
71///</summary>
72if(this.ViewStateTest1.皮肤样式_CustomViewState.BackColor==System.Drawing.Color.LightPink)
73{
74this.lbDisplay.Text+="this.ViewStateTest1.皮肤样式_CustomViewState.BackColor已经保存了视图状态,瞧,我自己的颜色就是保存的颜色,:)";
75this.lbDisplay.BackColor=System.Drawing.Color.LightPink;
76}
77else
78{
79this.lbDisplay.Text+="this.ViewStateTest1.皮肤样式_CustomViewState.BackColor没有保存视图状态,瞧,我的颜色还是白色,:(";
80}
81}
82}

4. 测试方案

a.下载示例代码后, 直接Ctrl + F5运行. 点"刷新"按钮button, 这时由于没有设置给控件值,

会显示如下页面:

Asp.net 2.0 自定义控件开发专题[详细探讨页面状态(视图状态和控件状态)机制及其使用场景](示例代码下载)...

b. 点击另一个按钮 "设置控件属性", 然后点击刷新按钮, 刷新页面, 这里视图状态已经保存了.

会出现如下图:

Asp.net 2.0 自定义控件开发专题[详细探讨页面状态(视图状态和控件状态)机制及其使用场景](示例代码下载)...

可以看到, 四种不同的类型只有第一种没有被存储到视图中. 因为第一种属性类型没有启用视图.

c. 将 Default.aspx.cs中Page_Load事件中的两行代码

//禁用页面视图状态测试
//Page.EnableViewState = false;

//禁用控件视图状态测试
//this.ViewStateTest1.EnableViewState = false;

任意移除一个注释语句, 再Ctrl+F5运行, 并按步骤 b 操作, 会出现以下运行结果:

Asp.net 2.0 自定义控件开发专题[详细探讨页面状态(视图状态和控件状态)机制及其使用场景](示例代码下载)...

表示四种类型的属性没有被视图存储, 很显然是因为Default.aspx.cs 中Page_Load中的代码禁

用了视图功能. 所以四种属性类型没有存储. 如果当页面禁用了视图状态, 但要求其属性类型

一定要存储怎么办? 这就要用到控件状态了, 下面就演示一下控件状态的用法.

2) . 控件状态

代码中注释也比较详细, 贴出代码:

1.自定义主控件测试类 ControlStateTest.cs 代码

1///<summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.****.net/ChengKing
4///