与刚接触 ASP
NET 页面的开发人员交谈时
他们通常向我提出的第一个问题就是
那个 ViewState 到底是什么?
他们的语气中流露出的那种感觉
就象我来到一家异国情调的餐馆
侍者端上一道我从未见过的菜肴时的那种感觉
既疑惑不解
又充满好奇
但肯定有人认为它不错
否则就不会提供了
所以
我会先尝一尝
或许会喜欢上它
尽管它看上去的确很古怪!
对于 ViewState 也是如此但是如果适应了它的风格您会发现在许多情况下您将乐于在自己的 ASPNET 应用程序中使用 ViewState因为它可以帮助您使用更少的代码完成更多的工作但是有时也会对 ViewState 完全弃之不用下面我们就这两种情况分别进行阐述不过让我们先回答什么是 ViewState 这个问题
答案ViewState 用于维护页面的 UI 状态
Web 是没有状态的ASPNET 页面也没有状态它们在到服务器的每个往返过程中被实例化执行呈现和处理作为 Web 开发人员您可以使用众所周知的技术(如以会话状态将状态存储在服务器上或将页面回传到自身)来添加状态下面我们以图 中的注册窗体为例进行论述
图 恢复回传的窗体值
从上图中可以看出我为便餐选择了一个无效的值此窗体与 Web 上的多数窗体一样友好它在出现错误的字段旁边显示一条有用的错误消息和一个星号而且窗体中还显示了我在其他文本框和下拉列表中输入的所有有效值这在某种程度上是可能的因为 HTML 窗体元素会在 HTTP 标头中将其当前值从浏览器发送到服务器您可以使用 ASPNET 跟蹤来查看回传的窗体值如图 所示
图 HTTP 窗体中回传的值(通过 ASPNET 跟蹤显示)
在 ASPNET 之前通过多次回传将值恢复到窗体字段中完全是页面开发人员的责任他们将不得不从 HTTP 窗体中逐个拾取回传值然后再将其推回字段中幸运的是现在 ASPNET 可以自动完成这项任务从而为开发人员免除了一项令人厌烦的工作同时也无需再为窗体编写大量的代码但这并不是 ViewState
ViewState(英文)是一种机制ASPNET 使用这种机制来跟蹤服务器控件状态值否则这些值将不作为 HTTP 窗体的一部分而回传例如由 Label 控件显示的文本默认情况下就保存在 ViewState 中作为开发人员您可以绑定数据或在首次加载该页面时仅对 Label 编程设置一次在后续的回传中该标签文本将自动从 ViewState 中重新填充因此除了可以减少繁琐的工作和代码外ViewState 通常还可以减少数据库的往返次数
ViewState 的工作原理
ViewState 确实没有什么神秘之处它是由 ASPNET 页面框架管理的一个隐藏的窗体字段当 ASPNET 执行某个页面时该页面上的 ViewState 值和所有控件将被收集并格式化成一个编码字符串然后被分配给隐藏窗体字段的值属性(即 <input type=hidden>)由于隐藏窗体字段是发送到客户端的页面的一部分所以 ViewState 值被临时存储在客户端的浏览器中如果客户端选择将该页面回传给服务器则 ViewState 字符串也将被回传在上面的图 中可以看到 ViewState 窗体字段及其回传的值
回传后ASPNET 页面框架将解析 ViewState 字符串并为该页面和各个控件填充 ViewState 属性然后控件再使用 ViewState 数据将自己重新恢复为以前的状态
关于 ViewState 还有三个值得注意的小问题
如果要使用 ViewState则在 ASPX 页面中必须有一个服务器端窗体标记 (<form runat=server>)窗体字段是必需的这样包含 ViewState 信息的隐藏字段才能回传给服务器而且该窗体还必须是服务器端的窗体这样在服务器上执行该页面时ASPNET 页面框架才能添加隐藏的字段
页面本身将 字节左右的信息保存在 ViewState 中用于在回传时将 PostBack 数据和 ViewState 值分发给正确的控件因此即使该页面或应用程序禁用了 ViewState仍可以在 ViewState 中看到少量的剩余字节
在页面不回传的情况下可以通过省略服务器端的 <form> 标记来去除页面中的 ViewState
充分利用 ViewState
ViewState 为跨回传跟蹤控件的状态提供了一条神奇的途径因为它不使用服务器资源不会超时并且适用于任何浏览器如果您要编写控件那么肯定需要了解如何在控件中维护状态(英文)
开发人员在编写页面时同样可以按照几乎相同的方式来利用 ViewState只是有时页面会包含不由控件存储的 UI 状态值您可以跟蹤 ViewState 中的值使用的编程语法与会话和高速缓存的语法类似
[Visual Basic]
保存在 ViewState 中
ViewState(SortOrder) = DESC
从 ViewState 中读取
Dim SortOrder As String = CStr(ViewState(SortOrder))
[C#]
// 保存在 ViewState 中
ViewState[SortOrder] = DESC;
// 从 ViewState 中读取
string sortOrder = (string)ViewState[SortOrder];