Comparaison entre états de contrôle et états d'affichage, exemple

Mise à jour : novembre 2007

Cet exemple montre comment créer un contrôle personnalisé nommé IndexButton, qui utilise l'état du contrôle pour conserver des informations d'état critiques d'une demande de page à l'autre. L'état de contrôle, introduit dans la version 2.0 d'ASP.NET, est comparable à l'état d'affichage bien qu'il en soit fonctionnellement indépendant. Un développeur de pages peut désactiver l'état d'affichage de la page ou d'un contrôle individuel de performance. Toutefois, l'état du contrôle ne peut pas être désactivé. L'état du contrôle sert à stocker les données essentielles d'un contrôle (comme le numéro de page d'un contrôle Pager), qui doivent rester disponibles lors de la publication pour que le contrôle fonctionne même si l'état d'affichage a été désactivé. L'infrastructure de page ASP.NET utilise par défaut le même élément masqué pour stocker l'état du contrôle dans la page que pour stocker l'état d'affichage. Même si l'état d'affichage est désactivé, ou si l'état est géré avec Session, l'état du contrôle est envoyé au client et retourné au serveur dans la page. Lors de la publication, ASP.NET désérialise le contenu de l'élément masqué et charge l'état du contrôle dans tous les contrôles inscrits pour le recevoir.

Remarque :

N'utilisez l'état du contrôle que pour de faibles volumes de données critiques, essentielles au contrôle d'une publication à l'autre. N'utilisez pas l'état du contrôle comme alternative à l'état d'affichage.

L'exemple illustre un contrôle personnalisé qui enregistre l'état à la fois dans l'état du contrôle et dans l'état d'affichage. Dans l'exemple, le contrôle IndexButton dérive de la classe Button et définit une propriété Index qu'il enregistre dans l'état du contrôle. Pour comparaison, IndexButton définit également une propriété IndexInViewState qu'il stocke dans le dictionnaire ViewState. Pour voir la différence entre l'état du contrôle et l'état d'affichage, utilisez le contrôle IndexButton, comme illustré dans la page .aspx répertoriée plus loin dans cette rubrique à la section « Page de test du contrôle IndexButton ».

Liste du code du contrôle 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);
                    }
                }
            }
        }

    }
}

Explication du code

L'implémentation du contrôle IndexButton illustre les trois tâches que vous devez effectuer pour permettre à un contrôle de participer à l'état du contrôle :

  • Substituez la méthode OnInit et appelez la méthode RegisterRequiresControlState pour effectuer une inscription dans la page afin de participer à l'état du contrôle. Cela doit être effectué à chaque demande.

  • Substituez la méthode SaveControlState pour enregistrer des données dans l'état du contrôle.

  • Substituez la méthode LoadControlState pour charger des données à partir de l'état du contrôle. Cette méthode appelle la méthode de classe de base qui apporte sa contribution à l'état du contrôle. Si le champ indexValue n'est pas égal à zéro et si l'état du contrôle de la classe de base n'est pas nul, la classe Pair est une structure de données pratique pour enregistrer et restaurer l'état du contrôle composé de deux parties.

Page de test du contrôle IndexButton

L'exemple suivant montre une page qui désactive l'état d'affichage en affectant à l'attribut EnableViewState la valeur false dans la directive @ Page. La page utilise le contrôle IndexButton et ajoute 1 aux valeurs des propriétés Index et IndexInViewState du contrôle dans le gestionnaire d'événements Page_Load. Les étiquettes de la page affichent les valeurs des propriétés Index et IndexInViewState.

Puisque la propriété Index est stockée dans l'état du contrôle, lequel ne peut pas être désactivé, la propriété Index conserve sa valeur lors de la publication et l'augmente d'un point chaque fois que la page est publiée sur le serveur. Par opposition, puisque la propriété IndexInViewState est stockée dans l'état d'affichage, lequel est désactivé pour la page, la valeur de la propriété IndexInViewState est toujours zéro par défaut.

<%@ 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>

Génération et utilisation de l'exemple

Pour plus d'informations sur la compilation et l'utilisation des exemples de contrôles personnalisés, consultez Exemples de création de contrôles serveur personnalisés.

Voir aussi

Concepts

Vue d'ensemble de l'état d'affichage ASP.NET

Recommandations sur la gestion d'état ASP.NET

Vue d'ensemble de la performance

Autres ressources

Développement de contrôles serveur ASP.NET personnalisés