清华电脑学堂:ASP.NET 4.5网站开发与应用实践教程
上QQ阅读APP看书,第一时间看更新

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排序效果