在ASP.NET框架中支持在回传中保存值的有2种方式:视图状态和控件状态
视图状态
ASP.NET中几个对象属性与控件最为密切的,就是ViewState了。
这里对其做下说明,任何可序列化类的实例均可添加到视图状态中,但是实际上,如果添加到名为_ViewState的隐藏表单域变的太大,会影响页面执行效率。
下面定义的控件包含了Text和ViewStateText属性,只有后者使用视图状态,那么ViewStateText属性的值会在页面回传中保存。
namespace ViewStateControl
{
/// <summary>
///支持视图状态
/// </summary>
public class SupportViewStateControls : WebControl
{
public string Text
{
get;
set;
}
public string ViewStateText
{
get
{
if (ViewState["ViewStateText"] == null)
return String.Empty;
else
return (string)ViewState["ViewStateText"];
}
set
{
ViewState["ViewStateText"] = value;
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("Text:" + Text);
writer.WriteBreak();
writer.Write("ViewStateText:" + ViewStateText);
writer.WriteBreak();
}
}
}
上面的代码中ViewStateText属性使用了Control类的ViewState集合在页面回传中保持并赋给ViewStateText属性的值。
在添加一个值到ViewState集合中时,其会自动填充至_VIEWSTATE隐藏表单域
Tip:因为视图状态在页面的InitComplete()后加载,在PreRenderComplete()后保存,也就是说不能在InitComplete()之前检索视图状态或者PreRenderComplete()后添加值至视图状态
控件状态
之所以在ASP.NET中引入控件概念,即使在视图状态被禁用时,仍可以用控件状态将信息保存在_VIEWSTATE隐藏表单域中
这句话很费解,举例来说明:一个GridView中包含了500条记录,为了改善性能,我们可以禁用视图状态,防止其将这些数据填充到_VIEWSTATE域里,
但是对于当前页数及选中的记录,我们仍希望GridView记住这些信息,这时就用到了控件状态。
namespace ViewStateControl
{
/// <summary>
///支持控件状态
/// </summary>
public class SupportControlStateControls : WebControl
{
public string ViewStateText
{
get
{
if (ViewState["ViewStateText"] == null)
return String.Empty;
else
return (string)ViewState["ViewStateText"];
}
set
{
ViewState["ViewStateText"] = value;
}
}
private string _controlStateText;
public string ControlStateText
{
get
{
return _controlStateText;
}
set
{
_controlStateText = value;
}
}
protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override object SaveControlState()
{
return _controlStateText;
}
protected override void LoadControlState(object savedState)
{
_controlStateText = (string)savedState;
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("ViewStateText:" +ViewStateText);
writer.WriteBreak();
writer.Write("ControlStateText:" + ViewStateText);
writer.WriteBreak();
}
}
}
这个代码用ViewStateText表示视图状态,ControlStateText属性表示控件状态,在OnInit()中RegisterRequiresControlState方法被调用指定该控件需要利用控件状态。SaveControlState和LoadControlState事件负责保存加载控件状态。
运行
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TestStateControl.aspx.cs" Inherits="TestViewStateControl" %>
<%@ Register TagPrefix="states" Namespace="ViewStateControl" %>
<!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>
<states:SupportControlStateControls ID="SupportControlStateControls1" EnableViewState="false" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Button" />
</div>
</form>
</body>
</html>
后台代码:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
SupportControlStateControls1.ViewStateText = "Hello";
SupportControlStateControls1.ControlStateText = "Hello";
}
}因为EnableViewState属性被关闭,所以单击按钮时,只有ControlStateText的属性值不会丢失
本文参考了《ASP.NET 3.5 揭秘(卷2)》