演练:开发和使用自定义服务器控件

ASP.NET 
控件状态与视图状态示例 

 

此示例演示如何创建一个名为 IndexButton 的自定义控件,该控件使用控件状态在多个页请求间维护关键状态信息。在 ASP.NET 2.0 版中引入的控件状态与视图状态类似,但功能上独立于视图状态。网页开发人员可能会出于性能原因而禁用整个页面或单个控件的视图状态,但他们不能禁用控件状态。控件状态是专为存储控件的重要数据(如一个页面控件的页数)而设计的,回发时必须用到这些数据才能使控件正常工作(即便禁用视图状态也不受影响)。默认情况下,ASP.NET 页框架将控件状态存储在页的一个隐藏元素中,视图状态也同样存储在此隐藏元素中。即使禁用视图状态,或是使用 Session 管理状态时,页面中的控件状态仍会传输至客户端,然后返回到服务器。在回发时,ASP.NET 会对隐藏元素的内容进行反序列化,并将控件状态加载到每个注册过控件状态的控件中。

Note注意

请仅对那些在回发过程中对控件至关重要的少量关键数据使用控件状态,而不要将控件状态作为视图状态的备用选项使用。

此示例阐释了一个同时在控件状态和视图状态中保存状态的自定义控件。在此示例中,IndexButton 控件派生自 Button 类,还定义了一个 Index 属性,并将该属性保存在控件状态中。为了进行比较,IndexButton 还定义了一个 IndexInViewState 属性,该属性存储在 ViewState 字典中。为了了解控件状态和视图状态之间的差异,请使用本主题后面的“IndexButton 控件的测试页”一节中列出的 .aspx 页来演示 IndexButton 控件。

IndexButton 控件的代码清单

Visual Basic
' 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 字段不为零,而且基类的控件状态也不为空,Pair 类便可作为方便的数据结构使用,用来保存和还原由两部分组成的控件状态。

IndexButton 控件的测试页

下面的示例阐释一个页面,该页通过在 @ Page 指令中将 EnableViewState 属性设置为 false 来禁用视图状态。该页使用 IndexButton 控件,并在 Page_Load 事件处理程序中,将控件的 IndexIndexInViewState 属性的值加 1。页中的标签显示 IndexIndexInViewState 两个属性的值。

由于 Index 属性存储在无法禁用的控件状态中,因而 Index 属性会在回发时维护其值,并在每次将页回发到服务器时加 1。相比之下,因为 IndexInViewState 属性存储在视图状态中,而页的视图状态已被禁用,所以 IndexInViewState 属性始终为默认值零。

Visual Basic
<%@ Page Language="VB" Trace="true" EnableViewState="false" %>
<script runat="server">
    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>
  <head id="Head1" runat="server">
    <title>IndexButton test page</title>
  </head>
  <body>
    <form id="form1" runat="server">
        Click the button:
        <aspSample:IndexButton Text="IndexButton" 
            ID="IndexButton1" runat="server"/>
      <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" %>
<script runat="server">
  void Page_Load(object sender, EventArgs e)
  {
    Label1.Text = (IndexButton1.Index++).ToString();
    Label2.Text = (IndexButton1.IndexInViewState++).ToString();
  }
</script>
<html>
  <head id="Head1" runat="server">
    <title>IndexButton test page</title>
  </head>
  <body>
    <form id="form1" runat="server">
        Click the button:
        <aspSample:IndexButton Text="IndexButton" 
            ID="IndexButton1" runat="server"/>
      <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>
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值