--普遍荒谬的认为 ViewState 对象保持着控件例如 TextBox 的值。
大多数 ASP.NET 的开发者认为 ASP.NET 的 ViewState 对象负责保持类似 TextBox 文本控件的值,因而这些值甚至在回传后还被保留着。但是这却不是这么回事。
我将用一个例子来解释。你可以下载项目文件(http://www.codeproject.com/aspnet/ViewState/ViewState.zip),建立一个名为 ViewState 的虚拟目录,并运行这个应用程序。让我们从一个 C# 语言的 Web 项目开始。
建立一个新的 ASP.NET Web 应用,然后在 WebForm 上放置以下控件:
放一个服务器 TextBox 控件,一个 HTML 服务器文本控件(带 runat=server 属性的普通 HTML 输入框),一个普通的 HTML 输入控件,和一个服务器端 Label 控件。4 个控件命名如下:
txtWebServerTest
txtHtmlServerTest
txtHtmlTest
lblTest
设置上边3个文本框的 Text 或 Value 属性为“Initial Text”。设置下边Label控件的 Text 属性为“Initial Label Value”。
设置第一个和最后一个控件的 EnableViewState 属性为 false。
在所有控件的下边,放置 2 个按钮控件(Button),分别设置它们的 Text 属性为“Change Label’s Text”和“Postback to Server”。在第一个按钮的点击事件里写入以下代码:
private void btnChangeLabel_Click(object sender, System.EventArgs e)
{
lblTest.Text = "Label's Text Changed";
}
在第二个按钮的点击事件里不写任何代码。它仅仅提交页面到服务器。
现在运行这个应用。你可以看到控件上你预先设置的初始化文本。
现在,改变所有文本框的文本,把他们设置为字符串“Changed Text”。再点击提交到服务器的按钮。可以看到前边的 2 个文本框保持了它们的值,尽管它们的 ViewState 属性被设置为 false。但是下一个文本框(简单的 HTML 输入控件),当页面被重新加载时,丢失了修改了的值。
大多数开发者可能期望所有的 3 个文本框都丢失它们更改了的值(“Changed Text”),并且在页面重新后,他们期望字符串“Initial Value”被重新写回到文本框中,因为我们已经把 ViewState 属性设置为 disabled 了。
这种行为的原因是,ViewState 是不负责存储诸如 TextBoxes, dropdowns, CheckBoxList 等这些继承自 IPostBackDataHandler 接口的控件的更改了的值的。在 Page_Init() 事件后,有个称为 LoadViewState 的事件,在这里 Page 类从隐藏的域 __VIEWSTATE 中为诸如 ViewState 属性为 enabled 的 Label 控件装载值。然后 LoadPostBackData 事件被出发,在这里 Page 类从 HTTP 提交头(POST headers)中装载继承自 IPostBackDataHandler 接口的控件的值。
现在,再次运行这个应用,这次点击“Change Label’s Text” 按钮。当页重新装载时,你将看到用程序改变(按钮的点击事件代码所为)的值丢失了,也就是说,我们没有看到 Label 的文本变成“Label's Text Changed”。而是再次看到 Label 的初始值。这是因为 Label 控件不是继承自 IPostBackDataHandler 接口,于是 ViewState 负责穿越回传期保持它的值。但又因为 ViewState 是 disabled 的, 所以 Label 丢失了点击“Change Label’s Text” 按钮时它被改变的文本。
现在使能 Label 控件的 ViewState 状态,在点击相同的按钮后,你会看到改变了的值(“Label's Text Changed”)。
所以我们断定,继承自 IPostBackDataHandler 接口的控件将保持它们的值,即使它们的 ViewState 状态被关闭,因为它们的值被保存在 HTTP 提交头里。