Partager via


Persistance des modifications côté client dans un contrôle qui n'est pas un formulaire

ECMAScript (JScript, JavaScript) côté client permet de suivre les changements d'état survenant côté client dans un contrôle qui n'est pas un élément formulaire. Un tel contrôle n'a aucun moyen pour publier des données sur le serveur par l'envoi d'un formulaire. L'exécution d'une publication d'événement est possible mais peut ne pas être significative. Ce problème peut être résolu par l'utilisation de champs de saisie masqués contenant des données pour le contrôle. Le contrôle doit émettre les champs de saisie masqués ainsi qu'un script qui injecte des informations d'état dans les champs masqués à un moment donné avant l'envoi du formulaire. Lorsque le contrôle est chargé, les données des champs masqués peuvent être extraites et utilisées par le contrôle. Pour activer ce mécanisme, un contrôle peut appeler la méthode RegisterHiddenField de sa Page afin d'émettre un champ masqué et implémenter l'interface IPostBackDataHandler pour récupérer la valeur du champ masqué et mettre à jour ses propriétés.

L'exemple suivant illustre ce scénario. Dans l'exemple, le contrôle (DHtmlControl) émet une étendue dont la couleur change sur le client lorsqu'elle est sélectionnée. Le contrôle émet une variable masquée dont la valeur est définie comme étant une variable booléenne par un script côté client afin d'indiquer si le contrôle a été sélectionné. Le contrôle expose une propriété booléenne (Selected) qui indique si le contrôle a été sélectionné sur le client. Le contrôle implémente l'interface IPostBackDataHandler, ce qui fait que lorsque la page est publiée sur le serveur, le contrôle peut lire la valeur du champ masqué et mettre à jour sa propriété Selected. Le contrôle expose également un événement (SelectedChanged) qu'il déclenche quand il est sélectionné sur le client.

Pour générer l'exemple, consultez les instructions fournies dans Exemples de contrôles serveur.

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Web;
using System.Web.UI;

namespace CustomControls
{
      public class DHtmlControl : Control, IPostBackDataHandler
      {
            public event EventHandler SelectedChanged;

            public string Text
            {
                  get
                  {
                        object obj = ViewState["Text"];
                        return (obj == null) ? String.Empty : (string)obj;
                  }

                  set
                  {
                        ViewState["Text"] = value;
                  }
            }

            public bool Selected
            {
                  get
                  {
                        object obj = ViewState["Selected"];
                        return (obj == null) ? false : (bool)obj;
                  }

                  set
                  {
                        ViewState["Selected"] = value;
                  }
            }

            protected string HelperID
            {
                  get
                  {
                        return "__" + ClientID + "_State";
                  }
            }

            protected override void OnInit(EventArgs e)
            {
                  base.OnInit(e);

                  if (Page != null)
                  {
                        Page.RegisterRequiresPostBack(this);
                  }
            }

            protected override void OnPreRender(EventArgs e)
            {
                  base.OnPreRender(e);

                  if (Page != null)
                  {
                        Page.RegisterHiddenField(HelperID, Selected.ToString());
                  }
            }

            protected override void Render(HtmlTextWriter writer)
            {
                  string postback = "";
                  if (Page != null)
                  {
                        postback = Page.GetPostBackEventReference(this) + ";";
                  }

                  string click = "onclick=\"var sel=getAttribute('selected'); sel = (sel.toLowerCase() == 'true'); sel=!sel; setAttribute('selected', sel.toString());this.style.backgroundColor=sel?'red':'white';" + HelperID +".value=sel.toString();" + postback + "\"";
                  string style = "style=\"cursor:hand;background-color:" + (Selected ? "red" : "white") + "\"";
                  string selected = "selected=\"" + Selected.ToString() + "\"";
                  writer.Write("<span " + style + " " + click + " " + selected + ">" + Text + "</span>");
            }

            bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
            {
                  string value = postCollection[HelperID];

                  if (value != null)
                  {
                        bool newValue = (String.Compare(value, "true", true) == 0);
                        bool oldValue = Selected;

                        Selected = newValue;

                        // If there is a change, raise a change event.
                        return (newValue != oldValue);
                  }

                  return false;
            }

            void IPostBackDataHandler.RaisePostDataChangedEvent()
            {
                  // There was a change,  so raise any events.
                  if (SelectedChanged != null)
                  {
                        SelectedChanged(this, EventArgs.Empty);
                  }
            }
      }
}
[Visual Basic]
Option Explicit
Option Strict

Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports Microsoft.VisualBasic

Namespace CustomControls
   Public Class DHtmlControl
      Inherits Control
      Implements IPostBackDataHandler
      Public Event SelectedChanged As EventHandler
      
      Public Property Text() As String
         Get
            Dim obj As Object = ViewState("Text")
            If obj Is Nothing Then
               Return String.Empty
            Else
               Return CStr(obj)
            End If
         End Get
         
         Set
            ViewState("Text") = value
         End Set
      End Property
      
      Public Property Selected() As Boolean
         Get
            Dim obj As Object = ViewState("Selected")
            If obj Is Nothing Then
               Return False
            Else
               Return CBool(obj)
            End If
         End Get
         
         Set
            ViewState("Selected") = value
         End Set
      End Property
      
      Protected ReadOnly Property HelperID() As String
         Get
            Return "__" & ClientID & "_State"
         End Get
      End Property
      
      Protected Overrides Sub OnInit(e As EventArgs)
         MyBase.OnInit(e)
         
         If Not (Page Is Nothing) Then
            Page.RegisterRequiresPostBack(Me)
         End If
      End Sub
      
      Protected Overrides Sub OnPreRender(e As EventArgs)
         MyBase.OnPreRender(e)
         
         If Not (Page Is Nothing) Then
            Page.RegisterHiddenField(HelperID, Selected.ToString())
         End If
      End Sub
      
      Protected Overrides Sub Render(writer As HtmlTextWriter)
         Dim postback As String = ""
         If Not (Page Is Nothing) Then
            postback = Page.GetPostBackEventReference(Me) & ";"
         End If
         
         Dim click As String = "onclick=""var sel=getAttribute('selected'); sel = (sel.toLowerCase() == 'true'); sel=!sel; setAttribute('selected', sel.toString());this.style.backgroundColor=sel?'red':'white';" & HelperID & ".value=sel.toString();" & postback & """"
         Dim style As String = "style=""cursor:hand;background-color:" & IIf(Selected, "red", "white").ToString() & """"
         Dim selectedPiece As String = "selected=""" & Selected.ToString() & """"
         writer.Write(("<span " & style & " " & click & " " & selectedPiece & ">" & Text & "</span>"))
      End Sub 
      
      Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As Boolean Implements IPostBackDataHandler.LoadPostData
         Dim value As String = postCollection(HelperID)
         
         If Not (value Is Nothing) Then
            Dim newValue As Boolean = String.Compare(value, "true", True) = 0
            Dim oldValue As Boolean = Selected
            
            Selected = newValue
            
            ' If there is a change, raise a change event.
            Return newValue <> oldValue
         End If
         
         Return False
      End Function
      
      Sub RaisePostDataChangedEvent() Implements IPostBackDataHandler.RaisePostDataChangedEvent
         ' There was a change, so raise any events.
         RaiseEvent SelectedChanged(Me, EventArgs.Empty)
      End Sub
   End Class 
End Namespace

Page utilisant le contrôle DHTML

La page suivante utilise le contrôle DHTML et attache un gestionnaire d'événements à son événement SelectedChanged. Notez que même si le contrôle figure entre des balises de formulaire, il ne constitue pas un élément formulaire et ne génère pas une paire nom/valeur pouvant être publiée sur le serveur.

<%@Register TagPrefix="Custom" NameSpace="CustomControls" Assembly="CustomControls" %>
<script language="C#" runat = "server" >
private void SelectedChangedHandler(object sender, EventArgs e)
{
label.Text = "You selected the DHTML control";
}
</script>
<html>
 <body>  
    <form id="Form1" method="post" runat="server">
       <Custom:DHtmlControl OnSelectedChanged = "SelectedChangedHandler" runat="server" Text="SelectMe" />
       <br>
       <asp:Label id = "label" runat = "server" />
    </form> 
  </body>
</html>
[Visual Basic]
<%@Register TagPrefix="Custom" NameSpace="CustomControls" Assembly="CustomControls" %>
<script language="VB" runat = "server" >
    Private Sub SelectedChangedHandler(sender As Object, e As EventArgs)
       label.Text = "You selected the DHTML control"
    End Sub
</script>
<html>
 <body>  
    <form id="Form1" method="post" runat="server">
       <Custom:DHtmlControl OnSelectedChanged = "SelectedChangedHandler" runat="server" Text="SelectMe" />
       <br>
       <asp:Label id = "label" runat = "server" />
    </form> 
  </body>
</html>

Voir aussi

Génération d'un script côté client pour la publication