5.6 ViewState对象
ViewState对象是ASP.NET中用来保存Web控件回传时状态值的一种机制。简单来说,ViewState用于维护页面的UI状态。它是类Control中的一个域,其他所有控件通过继承Control来获得ViewState功能。ViewState的类型是system.Web.UI.StateBag,它是一个名称/值的对象集合。
5.6.1 ViewState对象概述
ViewState对象并不神秘,如果要使用这个对象,则在“.aspx”页面中必须有一个服务器端窗体标记,即<form runat="server">。窗体字段是必需的,这样包含ViewState信息的隐藏字段才能回传给服务器。而且,form窗体还必须是服务器端的窗体,这样在服务器上执行页面时,ASP.NET页面框架才能添加隐藏的字段。实际上,在为窗体页面的form控件设置runat="server"时,这个form会被附加一个隐藏的_VIEWSTATE属性。_VIEWSTATE属性中存放了所有控件的ViewState中的状态值。
当请求某个页面时,ASP.NET把所有控件的状态序列化成一个字符串,然后作为窗体的隐藏属性送到客户端。当客户端把页面回传时,ASP.NET分析回传的窗体属性,并赋给控件对应的值。这些全部都是由ASP.NET负责的,因此对用户来说,这些操作全都是透明的。
ViewState可在控件、页、程序和全局配置中设置,其优先级别是控件>页面>程序>全局配置。开发者在使用ViewState时需要注意以下几点。
(1)ViewState的索引是大小写敏感的。
(2)ViewState信息不是网站共享的,因此不能够跨页面。
(3)保存在ViewState中的对象必须是可流化或者定义了TypeConverter。
(4)只有当页面回传(Server.Transfer())自身时,ViewState才是持续的,页面跳转(Response.Redirect())会使ViewState中的数据丢失。
(5)当禁止一个程序的ViewState时,这个程序的所有页面的ViewState也被禁止了。
(6)并不是所有的应用程序都需要保存控件状态信息,通过在页面的@Page指令中添加EnableViewState属性的值为false可以禁止整个页面的ViewState。
(7)TextBox控件的TextMode属性的值设置为Password时,其状态不会被保存在ViewState中。
注意
并不是所有的控件都可以禁止ViewState,如TextBox、CheckBox、CheckBoxList和RadioButtonList。这是因为它们的状态是通过IsPostBackEventHandler和IPostBackDataHandler接口处理,而不是ViewState的机制,因此,这些控件设置EnableViewState时没有效果。
5.6.2 使用ViewState对象
由于ViewState不使用服务器资源、不会超时,并且适用于任何浏览器,因此,它为跨回传跟踪控件的状态提供了一条神奇的途径。使用ViewState读取和写入数据的方式与Session和Application对象相似,格式如下。
ViewState["key"]="value"; //存放信息 string key=ViewState["key"].ToString(); //读取信息
如果要在Web窗体页面显示一个项目列表,而每个用户需要根据不同的列表排序。项目列表是静态的,因此,可以将这些页面绑定到相同的缓存数据集,而排序顺序只是用户特定的UI状态的一部分,这时,可以使用ViewState存储这种类型的值。下面通过范例10进行说明。
【范例10】
本范例利用GridView控件显示XML文档中的数据列表。使用ViewState存储一列静态数据的当前排序顺序,单击列表中的标题链接时,可按字段排序数据,再次单击链接,则按相反的顺序排序。步骤如下。
(1)创建名称为TestData的XML文档,它包含一系列的图书。部分内容如下。
<? xml version="1.0" standalone="yes"? > <NewDataSet> <Table> <pub_id>0736</pub_id> <pub_name>New Moon Books</pub_name> <city>Boston</city> <state>MA</state> <country>USA</country> </Table> <! -- 省略其他内容 --> </NewDataSet>
(2)在创建的Web窗体页中添加GridView控件,代码如下。
<asp:DataGrid ID="DataGrid1" runat="server" OnSortCommand="SortGrid" BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC" BackColor= "White" CellPadding="5" AllowSorting="True" Width="80%"> <HeaderStyle Font-Bold="True" ForeColor="White" BackColor= "#006699"></HeaderStyle> <ItemStyle ForeColor="Blue" BackColor="#569c66" /> </asp:DataGrid>
(3)打开窗体页面的后台添加代码,在ViewState中跟踪SortField属性,代码如下。
public string SortField { get { object o = ViewState["SortField"]; if (o == null) { return String.Empty; } return (string)o; } set { if (value == SortField) { SortAscending = ! SortAscending; // 与当前排序文件相同,切换排序方向 } ViewState["SortField"] = value; } }
(4)继续添加代码,在ViewState中跟踪SortAscending属性,代码如下。
public bool SortAscending { get { object o = ViewState["SortAscending"]; if (o == null) { return true; } return (bool)o; } set { ViewState["SortAscending"] = value; } }
(5)为页面的Load事件添加代码,页面首次加载时调用自定义的BindGrid()方法,代码如下。
protected void Page_Load(object sender, EventArgs e) { if (! Page.IsPostBack) { BindGrid(); } }
(6)BindGrid()方法读取XML文档中的数据,并且将数据绑定到GridView控件,代码如下。
public void BindGrid() { DataSet ds = new DataSet(); //获取数据 ds.ReadXml(Server.MapPath("TestData.xml")); DataView dv = new DataView(ds.Tables[0]); dv.Sort = SortField; //应用排序过滤器和方向 if (! SortAscending) { dv.Sort += " DESC"; } DataGrid1.DataSource = dv; //绑定GridView控件 DataGrid1.DataBind(); }
(7)为GridView控件的SortCommand事件添加代码,在该事件中将当前页的索引设置为0,然后设置SortField属性的值,最后调用BindGrid()方法重新实现绑定。代码如下。
protected void DataGrid1_SortCommand(object source, DataGridSortCommandEventArgs e) { DataGrid1.CurrentPageIndex = 0; SortField = e.SortExpression; BindGrid(); }
(8)运行页面查看效果,如图5-14所示。
图5-14 页面初始运行效果
(9)单击图5-14中的标题实现排序功能,如图5-15所示为根据city进行排序时的效果。
图5-15 根据city排序效果