什么是ViewState,在何处可以禁用ViewState
【考点】
ViewState的理解。
【出现频率】
★★★★☆
【解答】
ViewState用于保存页面中所有控件的回传时的状态数据,使WebForm程序类似于WinForm程序一样工作。ViewState可以在控件级别,页面级别,程序级别及全局配置中设置ViewState是否禁用,ViewState默认是启用的。
【分析】
本题主要考查面试者对ViewState的认识。ViewState也称为视图状态,ASP.NET使用ViewState这种机制来跟踪服务器控件状态值,否则这些值将不作为WEB窗体的一部分而回传。即页面中的控件被编程或用户填值等方式改变了状态后,当页面发生回传,这些状态仍然可以保持。因此,除了可以减少烦琐的工作和代码外,ViewState还可以减少数据库的读取频率。
在*.aspx页面中,如果form元素的“runat”属性值为“server”(这是VS 2005/VS 2008创建ASP.NET页面时的默认设置),该页面所生成的HTML页面即具备了ViewState的功能。ViewState具体表现为form元素中被添加一个隐藏的“id”属性为“__VIEWSTATE”的隐藏字段,这个字段中存放了所有控件在ViewState中的状态值。这个隐藏字段中的数据是64位编码的字符串,包含了一个集合,该集合中保存了当前页面上所有服务器控件的名称/值对,编程者可以编程通过ViewState访问这些值。
注意:ViewState不负责存储TextBox、Checkbox、CheckBoxList、RadioButtonList等这些实现了IPostBackDataHandler接口的控件所更改的状态值。在页面周期中的初始化过程(即Page_Init()事件后)中,在LoadViewState的事件中Page类从“id”属性为“__VIEWSTATE”的字段中为诸如启用了ViewState的控件装载值。紧接着,LoadPostBackData事件被触发,Page类从HTTP提交的头部信息中装载实现了IPostBackDataHandler接口的控件(如TextBox)状态值。当TextBox控件的“TextMode”属性为“Password”时,无法保存状态值(安全需要)。
如果页面仅用于回传,则页面内自定义的其他数据也可以存储于“id”属性为“__VIEWSTATE”的隐藏字段中。编程者只需直接访问ViewState属性即可,该属性返回了System.Web.UI.StateBag类对象的访问,可利用该对象的索引器以名称/值对的方式存取自定义数据。
在VS 2008中添加新的WEB窗体项到NetWeb项目,并命名为ViewState.aspx。,编写ViewState.aspx如代码11.12所示。代码11.12 ViewState测试页面:ViewState.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ViewState.aspx.cs" Inherits="NetWeb.ViewState" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" ID="tb" EnableViewState="false"></asp:TextBox>
<br />
<asp:Button runat="server" ID="btn" Text="回传页面" />
<hr />
TextBox的Text属性值:<asp:Label runat="server" ID="lb1" EnableViewState="false"></asp:Label>
<br />
自定义视图状态数据:<asp:Label runat="server" ID="lb2" EnableViewState="false"></asp:Label>
</div>
</form>
</body>
</html>
以上页面代码中添加了1个TextBox、1个Button和2个Label控件,并且将Button控件以外的3个控件设置了禁用ViewState。编写ViewState.aspx.cs如代码11.13所示。代码11.13 ViewState测试逻辑代码:ViewState.aspx.cs
using System;
………………………
namespace NetWeb
{
public partial class ViewState : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//第1次加载页面时将tb控件的Text属性值赋值给lb1控件
//同时将tb控件的Text属性值赋值给自定义视图状态的“MyWord”项中
if (!IsPostBack)
{
this.tb.Text = "TextBox的Text属性值";
this.lb1.Text = this.tb.Text;
this.ViewState["MyWord"] = this.tb.Text;
}
//每次加载页面都将自定义视图状态的“MyWord”项值赋值给lb2控件
this.lb2.Text = (string)ViewState["MyWord"];
}
}
}
如以上代码所示,TextBox控件保存的属性值完全不受ViewState被禁用的影响,而Label控件由于ViewState被禁用,所以回传页面后丢失了“Text”属性值。自定义视图状态的数据在每次回传页面后都一直被lb2控件显示出来,虽然lb2控件也被禁用了ViewState,但是自定义视图状态的数据赋值操作在每次页面加载时都会进行一次。
在解答中还提及了禁用ViewState多种方法,不同方法对应着不同的禁用范围。除了以上例子中直接在服务器控件标签中设置“EnableViewState”属性为“false”,还可以在@Page指令中设置这个属性以达到页面级禁用ViewState的目的。禁用整个WEB应用程序ViewState,修改Web.config中相应元素的属性即可,最后,禁用服务器全局的ViewState,修改.Net Framework安装目录下的machine.config即可。当禁用了ViewState以后,控件还可以通过control state(控件状态)保存状态数据,该属性一般用于自定义控件。
说明:ViewState只在页面内有效,不能跨页面使用。