了解控件的生命周期:
其中Init是由内而外,即先子控件后父控件,Load等相反。
在Init之前控件树根据声明语法已经生成
控件状态和视图状态:
控件状态是专门为维护控件的核心行为功能而设计的,而 ViewState 只包含维护控件内容 (UI) 的状态。应该按照这个规则设计控件状态。
先看一个例子:改自asp服务器控件和组件开发一书
PageTracker,用来跟踪页面会话状态和程序状态收到的点击数目,并计算页面往返时间
跟踪方式:
    }
控件代码:
    }
调用:
asp.net控件开发(一)简单属性、视图状态、控件状态<cc1:PageTracker ID="PageTracker3" runat="server" FormatString="{0}" TrackingMode="ByTripTime" />
asp.net控件开发(一)简单属性、视图状态、控件状态       

分析视图状态
视图状态只会把Diry的数据序列化到客户端,并不会序列化所有ViewState中的值,这样就减少了往返的数据量。如果禁用视图状态,就不会执行SaveViewState和LoadViewState。
第一次请求时(非Postback),视图状态从生成到序列化到客户端的过程:
1、在Init事件后,会调用TrackViewState方法,在此方法中,页面会自动调用控件的TrackViewState,并且把变化的属性存储到ViewState,保证了尽量少的值.此例子中ViewState此时只有两个值:FormtString和TrackingMode,其余的值还保持默认状态,并不会被加入ViewState。
2、Onload方法执行时,通过执行:“ ViewState["TimeStamp"= requestTime;",ViewState中会加入TimeStamp,值变为三个,虽然通过this.Visible = false把Visible设置为了False,可是在此时并不在ViewState中加入值,除非显示调用ViewState方法,否则到SaveViewState时才会加入到视图状态。
3、执行SaveViewState,因为Onload修改了Visible的属性,这时Visible被加入,此时ViewState的值变为四个。这个例子中值是页面框架自动保存到ViewState中的。如果自定义视图状态管理,必须自己实现Save,load。在此后控件状态的改变都不会被加入到视图状态中了,这是可以修改视图状态的最后机会。
4、解码序列化的视图状态:
通过查看生成的Html,解析出它的Viewstate值(部分):
asp.net控件开发(一)简单属性、视图状态、控件状态<Pair>
asp.net控件开发(一)简单属性、视图状态、控件状态                  
<ArrayList>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<IndexedString>TimeStamp</IndexedString>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<DateTime>2006-8-7 16:05:19</DateTime>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<IndexedString>Visible</IndexedString>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<Boolean>False</Boolean>
asp.net控件开发(一)简单属性、视图状态、控件状态                  
</ArrayList>
asp.net控件开发(一)简单属性、视图状态、控件状态                
</Pair>
其中Pair是存储ViewState的结构,第一个是状态名,第二个是值。从中可以看到视图状态只有两对值,而最后Save到ViewState的却是4对,为什么会如此呢?
原来,FormtString和TrackingMode没有被改写过,他们是没有必要被序列化到客户端的,从他们的IsItemDiry=fals可以看处来。
回发时(Postback)
在TraceViewState后会调用LoadViewState,LoadViewState会自动反序列化被编码的值(不自定义状态管理的情况下),并且合并TraceViewState生成的ViewState集合,本例中会是(Visible和TimeStamp+FormtString和TrackingMode)。
然后经过Onload,修改了timeStamp,Visible,再到SaveViewState被序列化到客户端。
生成的Html中的视图状态会是:
asp.net控件开发(一)简单属性、视图状态、控件状态<Pair>
asp.net控件开发(一)简单属性、视图状态、控件状态                  
<ArrayList>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<IndexedString>TimeStamp</IndexedString>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<DateTime>2006-8-7 17:05:19</DateTime>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<IndexedString>Visible</IndexedString>
asp.net控件开发(一)简单属性、视图状态、控件状态                    
<Boolean>True</Boolean>
asp.net控件开发(一)简单属性、视图状态、控件状态                  
</ArrayList>
asp.net控件开发(一)简单属性、视图状态、控件状态                
</Pair>
仍然只有两个,因为另外两个仍没有被修改过,不会被序列化。
简单属性:
简单属性是可以映射到文本的属性,他们一般有内置的TypeConvert,我们为他们启用声明性语法,不必做任何工作。因为.net内置支持.本例的TrackingMode等都是简单属性。枚举类型会在页面解析时自动映射到EnumConvert。
控件状态:
现在修改上面的例子,加上ControlState,只是示例作用:
asp.net控件开发(一)简单属性、视图状态、控件状态        protected override void OnInit(EventArgs e)
        }


控件状态实际上就是自定义的视图状态,现在简单的分析一下:
通过调用RegisterRequiresControlState 告诉容器Page,自定义控件将要使用控件状态。
LoadControlState和SaveContolState和ViewState的方法是一样的,他们会在ViewState的同名方法前被调用。

如果父控件有自己的控件状态,你又想把自己的控件状态加入到父控件。可以调用基类的SaveControlState 和LoadControlState 

asp.net控件开发(一)简单属性、视图状态、控件状态protected override object SaveControlState() 

可以用Triplet,和Pair存取值,也可以自己定义数组,象上面一样。

一段代码中的两个问题:
asp.net控件开发(一)简单属性、视图状态、控件状态      //Perform cleanup of the old storage.
asp.net控件开发(一)简单属性、视图状态、控件状态                 
//We have to check that the Page is not null
asp.net控件开发(一)简单属性、视图状态、控件状态                 
//because the control could be initialized
asp.net控件开发(一)简单属性、视图状态、控件状态                 
//before it is added to the control tree.
asp.net控件开发(一)简单属性、视图状态、控件状态                 
//Note that the Application and Session
asp.net控件开发(一)简单属性、视图状态、控件状态                 
//objects are not available in the designer.
asp.net控件开发(一)简单属性、视图状态、控件状态
                switch (TrackingMode)
                }

1、在Init之前究竟执行了什么?
我认为:会实例化子控件并且把他们加入控件树
上面代码的注释说,控件会在加入控件树之前被初始化,因此我们要保证Page不为Null。
我认为:在根据声明语法生成控件树的过程中,执行到此步骤时,控件树已经生成了一部分,即Page在此时不可能为Null,因此不用判断Null。可是跟踪发现Page确实是Null,原因可能是,控件树已经部分生成,Page已经生成。但在此时子控件是不能访问Page的,所以才会是Null。
下面是编译源:

           }

 

asp.net控件开发(一)简单属性、视图状态、控件状态protected virtual void AddParsedSubObject(object obj)

可以看到在执行Init前,会编译运行上面自动生成的编译源,这样以来第一个问题就彻底清楚了,也证明我上面的判断是正确的。


 

相关文章: