从Label和TextBox的角度看ViewState

对于很多不是很了解ViewState的人而言,可能有如下错误的理解:

  1. 禁用了页面viewstate后,页面中的所有控件的状态就不可以保存了;
  2. 所有控件都是通过viewstate来保持状态的;
  3. _ViewState隐藏字段内保存着所有控件的值等等
  4. ....


   其实上面的说法都是错误的,在开发的过程中,我们需要注意页面的生命周期以及方法、事件的时间顺序。

   ViewState是通过原型StateBag的TrackViewState()方法来追踪数据的,ASP.NET是在页面生命周期的OnInit阶段调用TrackViewState()方法,再调用了TrackViewState()方法后,ViewState的原型 StateBag开始跟踪值的变化,一旦相应的值发生变化,就会标记其为“dirty”,也就是脏数据,最后通过序列化操作等保存在_ViewState中,其格式为Base64。

很多文章中提示还应该注意:在调用TrackViewState()方法后,只要是出现了赋值操作那么就会使其被标记为脏数据,StateBag并不会判断赋值前后对应项的值是否出现了变化。

通过Lable和TextBox写了如下便于大多数人辨析ViewState例子:

<span style="font-family:SimSun;font-size:14px;"> </span><span style="font-family:SimSun;font-size:12px;"> <div>
        <asp:Label ID="lb1" runat="server" Text="0" ></asp:Label>
        <asp:TextBox ID="tb1" runat="server" Text="0"></asp:TextBox>
    </div>
       <asp:Button ID="Btn1" runat="server" OnClick="Btn1_Click" Text="Button" />
       <asp:Button ID="Btn2" runat="server" OnClick="Btn2_Click" Text="Button" /></span>


<span style="font-family: SimSun; font-size: 14px;"> </span><span style="font-family: SimSun;"> public partial class TestViewState : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

            Response.Write("lb1_pl:" + lb1.Text + "</br>");
            Response.Write("tb1_pl:" + tb1.Text + "</br>");
            lb1.Text = "1";
            tb1.Text = "1";
            Response.Write("lb1_pl_valuechange:" + lb1.Text + "</br>");
            Response.Write("tb1_pl_valuechange:" + tb1.Text + "</br>");

        }

        protected void Btn1_Click(object sender, EventArgs e)
        {
            Response.Write("lb1_btn1:" + lb1.Text + "</br>");
            Response.Write("tb1_btn1:" + tb1.Text + "</br>");
            lb1.Text = "2";
            tb1.Text = "2";
            Response.Write("lb1_btn1_valuechange:" + lb1.Text + "</br>");
            Response.Write("tb1_btn1_valuechange:" + tb1.Text + "</br>");
        }

        protected void Btn2_Click(object sender, EventArgs e)
        {
            Response.Write("lb1_btn2:" + lb1.Text + "</br>");
            Response.Write("tb1_btn2:" + tb1.Text + "</br>");
        }
    }</span>


通过设置lb1、tb1的EnableViewState属性的值的不同,统计页面第一次加载、Btn1_Click、Btn2_Click、再次Btn1_Click以及修改TextBox文本框中的值来记录lb1、tb1以及页面的ViewState隐藏字段_ViewState中Text的值

结果如下:


注释: *每一行五个小单元格代表五次Response.Write的值;“无” 代表不存在 ;ViewState  False代表将其控件的EnableViewState属性设置为False; 而Text(_ViewState)代表 页面viewstate中Text脏数据的值;

通过.net reflector 反编译查看Label Text如下:

[Bindable(true), Localizable(true), WebCategory("Appearance"), DefaultValue(""), WebSysDescription("Label_Text"), PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual string Text
{
    get
    {
        object obj2 = this.ViewState["Text"];
        if (obj2 != null)
        {
            return (string) obj2;
        }
        return string.Empty;
    }
    set
    {
        if (this.HasControls())
        {
            this.Controls.Clear();
        }
        this.ViewState["Text"] = value;
    }
}
 

结果分析:

  页面的_ViewState的内容格式为Base64,我们如果要查看可以使用 ViewStateDecoder来查看,在查看的过程中我们看到了pair,具体详细介绍可以看上面的第一篇文章http://www.cnblogs.com/wwan/archive/2010/11/18/1880357.html (介绍ViewState原理)

  先看Label 默认,也就是EnableViewState属性为True时

  1.  页面首次加载时,由于静态赋值text=0时,TraceViewState()并没有开始执行,赋值操作正常赋值,而在Page_Load事件执行时间在TraceViewState()之后,所以对Lable控件的赋值操作lb1.Text=“1” 会被ViewState的原型StateBag的捕获,并标记为dirty数据,通过序列化等一系列操作后,将Text值保存在页面的_ViewState隐藏字段中,所以值为1,此时页面的_ViewState保存着lb1现在的状态;
  2. 单击Btn1后,页面执行Page_Load和Btn1事件,Page_Load事件执行第一个Response.Write()时,由于页面的_ViewState保存着lb1现在的状态,通过将Base64编码的页面_ViewState内容进行反序列化等一系列操作,于是第一个Response值为1,后面对Lable控件的赋值操作lb1.Text=“1”,而btn1事件后,Lable控件的值最终会被赋值为2,如同前面一样,被ViewState的原型StateBag的捕获,并标记为dirty数据,所以最终页面的_ViewState保存着lb1的状态值为2;(注:无论原来的值与现在所赋的值是否相同,在TraceViewState()的追踪下,只要有赋值操作,就会将其标记为脏数据)
  3. 单击Btn2,再次单击Btn2分析方法如2一致;最终得如上图所示结论。

  当Label 的EnableViewState属性为False时

  1. 页面首次加载时,由于静态赋值text=0时,TraceViewState()并没有开始执行,赋值操作正常赋值,由于禁用了ViewState,Lable控件的赋值操作lb1.Text=“1” 时不会出现脏数据,页面的_ViewState隐藏字段中不会保存label控件的状态,也就是Text值不存在(_ViewState隐藏字段不仅仅包含标记为“dirty”数据,其实还包含一些其他的数据)
  2. 单击Btn1后,页面执行Page_Load和Btn1事件,由于ViewState被禁用,没有保存相应的状态,所以导致lb1在没有赋值的情况下值依旧为0;当有了赋值操作后,则会选择获取赋值,后面的任何操作都不会保存状态了,因为禁用了ViewState,所以在不赋值的情况下,page_load()事件里面的response.Write的值都为0;控件的赋值操作正常;_ViewState隐藏字段永远不会有脏数据。
  3. 单击Btn2、再次单击Btn2分析方法如2一致;最终得如上图所示结论。

接着我们看下TextBox如何,通过.net reflector 反编译查看,并没有与Lable相似的Text的出现,通过运行上面的例子会发现,无论如何设置EnableViewState,最终的结果都是一样的,不会因为ViewState的禁用而影响TextBox控件状态的保存。我们可以得出结论,TextBox的状态保存不是通过ViewState来进行的,实际上,他是一个特例,特例不止TextBox一个。

在微软的说明文档中有这样的解释:

即使在该控件的视图状态 (特性) 设置为False时,下面的服务器控件各请求之间保持它们的信息:

  • 文本框控件。
  • 复选框控件。
  • 单选按钮控件。
 这样就可以合理的解释TextBox为什么会发生如上的运行结果。更多见解可以 以这篇文章http://www.cnblogs.com/lixinkun/archive/2012/08/05/2624341.html 作为参考。


TextBox部分需要注意的是:

  禁用ViewState后,虽然并不会对TextBox的text赋值操作产生影响,但是会影响到TextBox控件的其它(比如设置它的width等等),这样就无法保存设置的相应的值的状态,需要注意。

  

  

   通过上面的案例解析应该可以对ViewState有一个基本的了解。如有错的地方,帮忙纠正。


延伸其他相关内容文章 :

    http://www.webjx.com/htmldata/2006-06-08/1149748147.html(ViewState和ControlState辨析)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值