共用方式為


控制項狀態和檢視狀態的比較範例

更新:2007 年 11 月

本範例示範如何建立名為 IndexButton 的自訂控制項,這個控制項會使用控制項狀態維護跨網頁要求的重要狀態資訊。在 ASP.NET 2.0 版中推出的控制項狀態類似於檢視狀態,但功能上和檢視狀態不同。網頁開發人員可以停用網頁的檢視狀態,或針對效能因素停用個別控制項的檢視狀態。但是,無法停用控制項狀態。控制項狀態的設計目的在於儲存控制項的基本資料 (例如頁面巡覽控制項的頁碼),在回傳時必須可以使用這些資料,這樣即使在停用檢視狀態時仍可讓控制項繼續運作。根據預設,ASP.NET 網頁架構會以儲存檢視狀態的相同隱藏項目,在網頁中儲存控制項狀態。即使已停用檢視狀態或者使用 Session 管理狀態時,網頁中的控制項狀態會傳到用戶端,然後傳回伺服器。回傳時,ASP.NET 會還原序列化隱藏項目的內容,並將控制項狀態載入已對控制項狀態登錄的每個控制項。

注意事項:

只對小量的重要資料使用控制項狀態,這些重要資料是跨回傳控制項的基本資料。請勿使用控制項狀態代替檢視狀態。

本範例說明在控制項狀態和檢視狀態中儲存狀態的自訂控制項。在範例中,IndexButton 控制項衍生自 Button 類別,並定義在控制項狀態中儲存的 Index 屬性。就比較而言,IndexButton 也定義了 IndexInViewState 屬性,並且將這個屬性存放在 ViewState 字典中。若要查看控制項狀態和檢視狀態之間的差異,請使用 IndexButton 控制項 (如本主題稍後章節「IndexButton 控制項的測試頁」中列出之 .aspx 網頁所示範)。

IndexButton 控制項的程式碼清單

' IndexButton.vb
Option Strict On
Imports System
Imports System.ComponentModel
Imports System.Security.Permissions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace Samples.AspNet.VB.Controls
    < _
    AspNetHostingPermission(SecurityAction.Demand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    AspNetHostingPermission(SecurityAction.InheritanceDemand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    ToolboxData("<{0}:IndexButton runat=""server""> </{0}:IndexButton>") _
    > _
    Public Class IndexButton
        Inherits Button
        Private indexValue As Integer

        < _
        Bindable(True), _
        Category("Behavior"), _
        DefaultValue(0), _
        Description("The index stored in control state.") _
        > _
        Public Property Index() As Integer
            Get
                Return indexValue
            End Get
            Set(ByVal value As Integer)
                indexValue = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Behavior"), _
        DefaultValue(0), _
        Description("The index stored in view state.") _
        > _
        Public Property IndexInViewState() As Integer
            Get
                Dim obj As Object = ViewState("IndexInViewState")
                If obj Is Nothing Then obj = 0
                Return CInt(obj)
            End Get
            Set(ByVal value As Integer)
                ViewState("IndexInViewState") = value
            End Set
        End Property

        Protected Overrides Sub OnInit(ByVal e As EventArgs)
            MyBase.OnInit(e)
            Page.RegisterRequiresControlState(Me)
        End Sub

        Protected Overrides Function SaveControlState() As Object
            ' Invoke the base class's method and
            ' get the contribution to control state
            ' from the base class.
            ' If the indexValue field is not zero
            ' and the base class's control state is not null,
            ' use Pair as a convenient data structure
            ' to efficiently save 
            ' (and restore in LoadControlState)
            ' the two-part control state
            ' and restore it in LoadControlState.

            Dim obj As Object = MyBase.SaveControlState()

            If indexValue <> 0 Then
                If obj IsNot Nothing Then
                    Return New Pair(obj, indexValue)
                Else
                    Return indexValue
                End If
            Else
                Return obj
            End If
        End Function

        Protected Overrides Sub LoadControlState(ByVal state As Object)
            If (state IsNot Nothing) Then
                Dim p As Pair = TryCast(state, Pair)
                If p IsNot Nothing Then
                    MyBase.LoadControlState(p.First)
                    indexValue = CInt(p.Second)
                Else
                    If (TypeOf (state) Is Integer) Then
                        indexValue = CInt(state)
                    Else
                        MyBase.LoadControlState(state)
                    End If
                End If
            End If
        End Sub

    End Class
End Namespace
// IndexButton.cs
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Samples.AspNet.CS.Controls
{
    [
    AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level=AspNetHostingPermissionLevel.Minimal),
    ToolboxData("<{0}:IndexButton runat=\"server\"> </{0}:IndexButton>")
    ]
    public class IndexButton : Button
    {
        private int indexValue;

        [
        Bindable(true),
        Category("Behavior"),
        DefaultValue(0),
        Description("The index stored in control state.")
        ]
        public int Index
        {
            get
            {
                return indexValue;
            }
            set
            {
                indexValue = value;
            }
        }

        [
        Bindable(true),
        Category("Behavior"),
        DefaultValue(0),
        Description("The index stored in view state.")
        ]
        public int IndexInViewState
        {
            get
            {
                object obj = ViewState["IndexInViewState"];
                return (obj == null) ? 0 : (int)obj;
            }
            set
            {
                ViewState["IndexInViewState"] = value;
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            Page.RegisterRequiresControlState(this);
        }

        protected override object SaveControlState()
        {
            // Invoke the base class's method and
            // get the contribution to control state
            // from the base class.
            // If the indexValue field is not zero
            // and the base class's control state is not null,
            // use Pair as a convenient data structure
            // to efficiently save 
            // (and restore in LoadControlState)
            // the two-part control state
            // and restore it in LoadControlState.

            object obj = base.SaveControlState();

            if (indexValue != 0)
            {
                if (obj != null)
                {
                    return new Pair(obj, indexValue);
                }
                else
                {
                    return (indexValue);
                }
            }
            else
            {
                return obj;
            }
        }

        protected override void LoadControlState(object state)
        {
            if (state != null)
            {
                Pair p = state as Pair;
                if (p != null)
                {
                    base.LoadControlState(p.First);
                    indexValue = (int)p.Second;
                }
                else
                {
                    if (state is int)
                    {
                        indexValue = (int)state;
                    }
                    else
                    {
                        base.LoadControlState(state);
                    }
                }
            }
        }

    }
}

程式碼討論

IndexButton 控制項的實作說明三項工作,您必須執行這三項工作以讓控制項參與控制項狀態:

  • 覆寫 OnInit 方法並叫用 RegisterRequiresControlState 方法,向網頁註冊以參與控制項狀態。每個要求都必須這樣執行。

  • 覆寫 SaveControlState 方法,將資料儲存在控制項狀態中。

  • 覆寫 LoadControlState 方法,從控制項狀態載入資料。這個方法會呼叫基底類別方法,並取得控制項狀態的基底類別比重。如果 indexValue 欄位不是零,而且基底類別的控制項狀態不是 null,Pair 類別會當做適當的資料結構,以儲存和還原兩部分的控制項狀態。

IndexButton 控制項的測試頁

下列範例示範在 @ Page 指示詞中,將 EnableViewState 屬性設為 false 即可停用檢視狀態的網頁。網頁使用 IndexButton 控制項,並在 Page_Load 事件處理常式之控制項的 Index 和 IndexInViewState 屬性值中加 1。網頁中的標籤會顯示 Index 和 IndexInViewState 屬性的值。

由於 Index 屬性存放在控制項狀態中 (無法停用),Index 屬性會在回傳時維護其值,並在每次網頁回傳至伺服器時加一。相比之下,由於 IndexInViewState 屬性存放在檢視狀態中 (可對網頁停用),IndexInViewState 屬性永遠會使用預設值零。

<%@ Page Language="VB" Trace="true" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
    Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        Label1.Text = IndexButton1.Index.ToString()
        Label2.Text = IndexButton1.IndexInViewState.ToString()
        IndexButton1.Index += 1
        IndexButton1.IndexInViewState += 1
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" >
    <title>IndexButton test page</title>
  </head>
  <body>
    <form id="form1" >
        Click the button:
        <aspSample:IndexButton Text="IndexButton" 
            ID="IndexButton1" />
      <br />
      <br />
      The value of the Index property of IndexButton is:<br />
      <asp:Label ID="Label1" Runat="server" Text="Label">
      </asp:Label>
      <br />
      <br />
      The value of the IndexInViewState property of IndexButton is:
      <br />
      <asp:Label ID="Label2" Runat="server" Text="Label">
      </asp:Label>
      <br />
    </form>
  </body>
</html>
<%@ Page Language="C#" Trace="true" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
  void Page_Load(object sender, EventArgs e)
  {
    Label1.Text = (IndexButton1.Index++).ToString();
    Label2.Text = (IndexButton1.IndexInViewState++).ToString();
  }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" >
    <title>IndexButton test page</title>
  </head>
  <body>
    <form id="form1" >
        Click the button:
        <aspSample:IndexButton Text="IndexButton" 
            ID="IndexButton1" />
      <br />
      <br />
      The value of the Index property of IndexButton is:<br />
      <asp:Label ID="Label1" Runat="server" Text="Label">
      </asp:Label>
      <br />
      <br />
      The value of the IndexInViewState property of IndexButton is:
      <br />
      <asp:Label ID="Label2" Runat="server" Text="Label">
      </asp:Label>
      <br />
    </form>
  </body>
</html>

建置及使用範例

如需編譯及使用自訂控制項範例的詳細資訊,請參閱建置自訂伺服器控制項範例

請參閱

概念

ASP.NET 檢視狀態概觀

ASP.NET 狀態管理建議事項

效能概觀

其他資源

開發自訂的 ASP.NET 伺服器控制項