深入理解 viewstate
上个星期写了一篇《控件 viewstate 属性的值保存去哪里了》,解释了control.viewstate最终还是通过control.saveviewstate和control.loadviewstate这两个方法存取的。文章中有一句话可能会让大家感到疑惑的:“我们在oninit之后使用this.viewstate[key]读写时该属性都为true”,其中“该属性”指stateitem.isdirty。到底为什么isdirty属性在oninit之后总是为true呢?参考了truly understanding viewstate,我终于明白到其实它并非总是为true,详细原因请听我慢慢说。
首先要让大家来看的是statebag.trackviewstate方法,这个方法在控件oninit时就会被调用,而它的作用就是让statebag开始跟踪stateitem的变化,任何变化都将导致该stateitem的isdirty属性变为true。也就是说,在oninit之前,isdirty属性是false的,并且无论你如何设置value属性的值都不会改变isdirty属性。在oninit之后,isdirty属性也保持着false,直到你第一次改变value属性的值(指通过this.viewstate[key]的方法改变)。到了saveviewstate的阶段,只有isdirty属性为true的stateitem才会被保存下来。
为什么要如此设计呢?例如一个通过声明性定义的label的text属性,在aspx中它被赋了初值,然后该初值自然通过viewstate["text"]来持久。在下一个页面生命周期,首先oninit时这个label的text属性会加载aspx中声明性定义的初值,然后loadviewstate时会用viewstate中读取到的viewstate["text"]来覆盖它。然而除非你在上一个页面生命周期以编程的方式改变了text属性,否则viewstate["text"]还是初值,那么你就是用viewstate["text"]保存初值去覆盖声明性定义的初值,同一个值这样覆盖完全没意义,而且还浪费了viewstate的空间。为了解决这个资源浪费的问题,凡是声明性定义之后没改变到的值就不应该使用viewstate来持久,而详细的实现就是上面说的trackviewstate机制了。
说到这里,control.viewstate已经解释完毕,如果你是控件设计者你可以放心地按以下方式把控件属性存放到viewstate中:
public string text
{
get {return this.viewstate["text"] as string;}
set {this.viewstate["text"] = value;}
}
它的内部机制会懂得区分你存进去的值是不是aspx上声明性定义的初值,然后决定是否持久该值。同时,如果你在任何阶段想改变一个viewstate值是否持久的决定,可以通过viewstate.setitemdirty(key, dirty)来改变,这基本上已经满足了所有控件开发人员的需求。
http://www.cnblogs.com/cathsfz/archive/2006/10/29/543695.html