Création de composants clients non visuels personnalisés

Mise à jour : novembre 2007

Cette rubrique vous indique comment créer un composant AJAX client non visuel qui dérive de la classe de base client Sys.Component dans ASP.NET, et comment utiliser le composant dans une page.

Dans ce didacticiel, vous allez apprendre à effectuer les opérations suivantes.

  • Utiliser le modèle de design prototype pour définir une classe de composant non visuel dans un script ECMAScript (JavaScript).

  • Enregistrer un composant non visuel comme une classe dérivée de la classe de base Component.

  • Initialiser la classe Component de base du composant non visuel et appeler ses méthodes.

  • Créer des propriétés qui déclenchent une notification de modifications.

  • Utiliser le composant dans une page et créer une liaison avec les événements du composant.

La vue d'ensemble fournit l'exemple d'un temporisateur (timer) comme composant client non visuel. Le temporisateur déclenche des événements que vous pouvez gérer.

Cette rubrique se concentre sur des objets clients à base de composants non visuels. Ces composants dérivent de Component et, en général, n'ont aucune représentation par interface utilisateur. Deux types supplémentaires d'objets composants clients ASP.NET AJAX étendent les fonctionnalités de base des composants : les comportements qui dérivent de Sys.UI.Behavior et les contrôles qui dérivent de Sys.UI.Control. Le tableau suivant résume les différences entre les composants, les comportements et les contrôles.

Types de composants objets clients

Résumé

Composants

  • Dérivent de la classe de base Component.

  • N'ont en général aucune représentation graphique, per exemple un composant temporisateur (timer) qui déclenche des événements à intervalles réguliers mais n'est pas visible sur la page.

  • N'ont pas d'éléments DOM associés.

  • Encapsulent le code client destiné à une réutilisation par d'autres applications.

Comportements

  • Dérivent de la classe de base Behavior base class qui étend la classe de base Component.

  • Étendent le comportement d'éléments DOM, tel que le comportement filigrane qui peut être lié à une zone de texte existante.

  • Peuvent créer des éléments d'interface, bien qu'ils ne modifient en général pas le comportement de base de l'élément DOM auquel ils sont associés.

  • Sont accessibles directement depuis l'élément DOM par le biais d'un attribut personnalisé (expando). L'attribut aura le nom du comportement si celui-ci a été défini ; sinon, il portera le nom du type (pas complet).

  • Ne nécessitent pas d'association avec un autre objet client, tel qu'une classe dérivée de la classe Control ou Behavior.

  • Peuvent référencer dans leur propriété element un élément HTML qui peut être ou non un contrôle.

Contrôles

  • Dérivent de la classe de base Control base class qui étend la classe de base Component.

  • Représentent un élément DOM comme un objet client, typiquement en modifiant le comportement habituel de l'élément DOM d'origine pour offrir de nouvelles fonctionnalités. Par exemple, un contrôle de menu peut lire des éléments li d'un élément ul comme ses données sources mais n'affichera pas de liste à puce.

  • Sont accessibles directement depuis l'élément DOM via le contrôle expando.

Composants requis

Pour exécuter l'exemple de cette rubrique, vous aurez besoin des éléments suivants.

Création des fonctionnalités de base d'un composant client non visuel

Un composant client ASP.NET AJAX non visuel encapsule du code JavaScript destiné à être réutilisable dans plusieurs applications. Un exemple d'un composant non visuel est un composant temporisateur (timer) qui déclenche des événements à des intervalles définis.

En dérivant de la classe de base Component, votre composant personnalisé hérite automatiquement des fonctionnalités suivantes :

  • Un modèle compatible avec plusieurs navigateurs pour gérer les liaisons de gestionnaires aux événements d'objets clients.

  • Un enregistrement automatique du composant dans l'application cliente comme un objet jetable qui implémente l'interface Sys.IDisposable.

  • La capacité à déclencher des événements de notification lorsque les propriétés sont modifiées.

  • La capacité d'exécuter le traitement par lots de paramètres de propriétés de composants. Cette méthode est plus efficace en termes de taille de script et de temps de traitement que de gérer toute la logique dans des accesseurs de propriétés set et get individuels.

  • Une substitution de la méthode Sys.Component.initialize pour initialiser toutes les propriétés et écouteurs d'événements.

Implémentation d'un composant client dérivé de la classe Component

Pour implémenter un composant client personnalisé dérivé de Component, il vous suffit de suivre les étapes principales ci-après.

  • Définissez une classe de composant à l'aide du modèle de design prototype.

  • Initialisez l'instance Component de base du composant.

  • Exposez tous accesseurs de propriété et, si vous le souhaitez, déclenchez un événement de notification propertyChanged.

  • Substituez la méthode dispose pour libérer les ressources, effacer les gestionnaires d'événements par exemple.

Les sections suivantes fournissent plus de détails sur chaque étape de l'implémentation.

Définition d'une classe de composant en utilisant le modèle de design prototype

Une classe cliente ASP.NET AJAX, qui inclut une classe de composant, est définie dans JavaScript à l'aide du modèle de design prototype. Pour définir une classe de composant en utilisant le modèle de design prototype, effectuez les opérations suivantes :

  • enregistrez l'espace de noms pour votre classe de composant ;

  • créez la fonction constructeur du composant et, dans ce constructeur, définissez tous les champs privés et affectez-leur des valeurs initiales ;

  • définissez le prototype du composant ;

  • enregistrez la fonction composant en tant que classe dérivée de Component.

Pour plus d'informations, consultez Création d'une classe Component cliente à l'aide du modèle de prototype.

Initialisation de la classe de base

Dans la fonction constructeur du composant, vous appelez la méthode héritée Type.initializeBase pour initialiser le type de base de votre classe enregistrée. Une classe de composant non visuel est enregistrée comme une classe possédant un type de base Component. Lorsque la classe de base Component est initialisée ses méthodes sont disponibles au composant et il enregistre automatiquement le composant comme un objet jetable auprès de l'application ASP.NET AJAX. Pour plus d'informations, consultez Sys.IDisposable, interface.

Toute classe de composant qui dérive de Component doit initialiser sa classe de base depuis le constructeur. Typiquement, vous appelez initializeBase avant l'exécution de tout autre code dans le constructeur. L'exemple suivant montre la fonction constructeur d'un composant non visuel qui dérive de Component.

Samples.SimpleComponent = function()
{
    Samples.SimpleComponent.initializeBase(this);
}

Définition de propriétés et déclenchement de notifications des modifications de propriétés

Dans la classe de votre composant, vous définissez des propriétés auxquelles les développeurs peuvent accéder par des fonctions get et set. Un composant ASP.NET AJAX qui dérive de Component hérite de la méthode Sys.Component.raisePropertyChanged, que vous appelez pour déclencher un événement propertyChanged pour les propriétés de votre composant. Les développeurs Web qui utilisent votre composant peuvent ensuite créer une liaison avec ces événements. Pour plus d'informations, consultez Définition de propriétés de composants personnalisées et déclenchement d'événements PropertyChanged.

Initialisation de propriétés et d'écouteurs d'événements

Si votre composant personnalisé doit initialiser des propriétés ou des écouteurs d'événements, vous devez substituer la méthode Sys.Component.initialize dans le prototype du composant. Par exemple, un composant non visuel qui dérive de Component peut assigner un délégué à un événement tel que window.onFocus. Pour finir, vous appelez la méthode de base initialize pour permettre à la classe de base du composant d'achever l'initialisation.

ASP.NET fournit des classes et des méthodes permettant la gestion d'événements standard pour les composants et pour les éléments DOM. Pour gérer les événements de votre composant, utilisez la classe Sys.EventHandlerList. Par exemple, liez des événements à l'aide de la méthode Sys.EventHandlerList.addHandler et libérez-les en utilisant la méthode Sys.EventHandlerList.removeHandler. Pour plus d'informations, consultez Sys.EventHandlerList, classe.

Pour gérer des gestionnaires d'événements pour des éléments DOM ou l'objet window, utilisez la classe Sys.UI.DomEvent. Par exemple, vous pouvez lier et annuler la liaison des gestionnaires d'événements à l'aide des méthodes addHandler Sys.UI.DomEvent et removeHandler Sys.UI.DomEvent, respectivement. Pour plus d'informations, consultez Sys.UI.DomEvent, classe.

Libération des ressources

Si votre composant personnalisé doit libérer des ressources avant la destruction du composant, substituez la méthode dispose et libérez les ressources dans la méthode substituée. Cela permet de s'assurer que les ressources sont libérées juste avant la suppression du composant. Parmi les ressources qui doivent être libérées on peut trouver les gestionnaires pour les événements DOM. En vérifiant que toutes références circulaires possibles entre les éléments DOM et l'objet composant sont supprimées, vous vous assurez que l'objet peut être effacé de la mémoire. Pour plus d'informations, consultez Libération de ressources de composant.

Utilisation d'un composant non visuel dans une page

Pour utiliser un composant client personnalisé dans une page ASP.NET AJAX, effectuez les opérations suivantes.

  • Enregistrez la bibliothèque de scripts du composant dans la page Web.

  • Créez une instance composant.

Les sections suivantes fournissent plus de détails sur chacune de ces étapes.

Enregistrement de la bibliothèque de scripts du composant dans la page Web

Vous pouvez enregistrer les scripts requis par un contrôle client de la page avec un contrôle ScriptManager, soit de façon déclarative soit par programme. L'exemple suivant montre le balisage déclaratif pour un contrôle ScriptManager qui enregistre un script composant.

<form id="form1" >
  <asp:ScriptManager  ID="ScriptManager01">
    <scripts>
      <asp:ScriptReference path="DemoTimer.js" />
    </scripts>
  </asp:ScriptManager>
</form>

L'élément asp:ScriptManager contient un élément asp:ScriptReference dans un nœud scripts. L'attribut path de l'élément asp:ScriptReference référence le chemin d'accès du fichier .js (dans l'exemple, DemoTimer.js) qui définit une classe de composant. Pour plus d'informations, consultez Assignation dynamique de références de script et la vue d'ensemble de la classe ScriptManager.

Comme alternative à l'enregistrement de fichiers de script à l'aide du contrôle ScriptManager, vous pouvez gérer les composants clients en utilisant un contrôle serveur personnalisé qui implémente l'interface IScriptControl. Le contrôle serveur personnalisé peut enregistrer automatiquement les scripts de composant requis et exposer le balisage déclaratif servant à définir des propriétés de composant et des liaisons d'événements. Si vous enregistrez des scripts à l'aide d'un contrôle serveur personnalisé, vous rendrez l'utilisation de votre composant plus aisée pour le développeur. Pour plus d'informations, consultez la vue d'ensemble de la classe IScriptControl.

Remarque :

Tous les fichiers de script autonomes à enregistrer avec le contrôle ScriptManager doivent appeler la méthode notifyScriptLoaded pour avertir l'application que le chargement du script est terminé. Les scripts incorporés dans un assembly ne doivent, dans la plupart des cas, pas appeler cette méthode. Pour plus d'informations, consultez Sys.Application.notifyScriptLoaded, méthode.

Création d'une instance de composant personnalisé

Vous instanciez un composant client en appelant la méthode Sys.Component.create ou le raccourci $create. Vous passez des paramètres à la méthode $create pour spécifier le type de composant. Vous passez également un objet JSON qui contient une valeur d'ID requise et des valeurs initiales facultatives de propriétés ainsi que des liaisons de gestionnaire d'événements facultatives.

L'exemple suivant illustre la manière d'instancier un composant par l'appel de la méthode $create.

var app = Sys.Application;
app.add_init(applicationInitHandler);

function applicationInitHandler(sender, args) 
{
    $create(Demo.Timer, {enabled:true,id:"demoTimer1", interval:2000}, 
        {tick:OnTick}, null);
}

Pour plus d'informations, consultez Sys.Component.create, méthode et $create, méthode de Sys.Component.

Création du composant personnalisé Demo.Timer

De cette section, vous créerez un composant client personnalisé nommé Demo.Timer qui étend la classe de base Component, puis vous utiliserez le composant dans une page. Demo.Timer est un composant Timer simple qui définit un événement tick, expose une propriété enabled et une propriété interval et déclenche un événement de notification de modifications pour la propriété interval. Un développeur qui utilise le composant Demo.Timer peut gérer l'événement tick. Le développeur peut également se lier à l'événement de modification de propriété et agir à chaque mise à jour de la propriété interval.

Pour créer le code du composant Demo.Timer

  1. Dans le répertoire racine d'une application Web ASP.NET AJAX, créez un fichier nommé DemoTimer.js.

  2. Ajoutez le code suivant au fichier :

    Type.registerNamespace("Demo");
    
    Demo.Timer = function() {
        Demo.Timer.initializeBase(this);
    
        this._interval = 1000;
        this._enabled = false;
        this._timer = null;
    }
    
    Demo.Timer.prototype = {
        // OK to declare value types in the prototype
    
    
        get_interval: function() {
            /// <value type="Number">Interval in milliseconds</value>
            return this._interval;
        },
        set_interval: function(value) {
            if (this._interval !== value) {
                this._interval = value;
                this.raisePropertyChanged('interval');
    
                if (!this.get_isUpdating() && (this._timer !== null)) {
                    this._restartTimer();
                }
            }
        },
    
        get_enabled: function() {
            /// <value type="Boolean">True if timer is enabled, false if disabled.</value>
            return this._enabled;
        },
        set_enabled: function(value) {
            if (value !== this.get_enabled()) {
                this._enabled = value;
                this.raisePropertyChanged('enabled');
                if (!this.get_isUpdating()) {
                    if (value) {
                        this._startTimer();
                    }
                    else {
                        this._stopTimer();
                    }
                }
            }
        },
    
        // events
        add_tick: function(handler) {
            /// <summary>Adds a event handler for the tick event.</summary>
            /// <param name="handler" type="Function">The handler to add to the event.</param>
            this.get_events().addHandler("tick", handler);
        },
        remove_tick: function(handler) {
            /// <summary>Removes a event handler for the tick event.</summary>
            /// <param name="handler" type="Function">The handler to remove from the event.</param>
            this.get_events().removeHandler("tick", handler);
        },
    
        dispose: function() {
            // call set_enabled so the property changed event fires, for potentially attached listeners.
            this.set_enabled(false);
            // make sure it stopped so we aren't called after disposal
            this._stopTimer();
            // be sure to call base.dispose()
            Demo.Timer.callBaseMethod(this, 'dispose');
        },
    
        updated: function() {
            Demo.Timer.callBaseMethod(this, 'updated');
            // called after batch updates, this.beginUpdate(), this.endUpdate().
            if (this._enabled) {
                this._restartTimer();
            }
        },
    
        _timerCallback: function() {
            var handler = this.get_events().getHandler("tick");
            if (handler) {
                handler(this, Sys.EventArgs.Empty);
            }
        },
    
        _restartTimer: function() {
            this._stopTimer();
            this._startTimer();
        },
    
        _startTimer: function() {
            // save timer cookie for removal later
            this._timer = window.setInterval(Function.createDelegate(this, this._timerCallback), this._interval);
        },
    
        _stopTimer: function() {
            if(this._timer) {
                window.clearInterval(this._timer);
                this._timer = null;
            }
        }
    }
    
    Demo.Timer.registerClass('Demo.Timer', Sys.Component);
    
    // Since this script is not loaded by System.Web.Handlers.ScriptResourceHandler
    // invoke Sys.Application.notifyScriptLoaded to notify ScriptManager 
    // that this is the end of the script.
    if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
    
    

Explication du code

Le code enregistre l'espace de noms Demo en appelant la méthode Type.registerNamespace. Il est recommandé de déclarer et d'initialiser tous les champs privés dans le constructeur, comme interval dans cet exemple. Le constructeur appelle la méthode héritée initializeBase afin que les méthodes de la classe de base Component soient disponibles. La classe de base initialisée enregistre ensuite l'instance Demo.Timer auprès de l'application cliente comme objet jetable.

Dans le prototype, le code déclare et initialise deux propriétés publiques : interval et enabled. Les définitions de propriétés comprennent des champs privés comprenant les valeurs et des accesseurs set et get pour chacune des ces propriétés. Dans la méthode d'accesseur set de chaque propriété publique, le code déclenche un événement propertyChanged en appelant la méthode raisePropertyChanged. Cet événement avertit le développeur Web lorsque la propriété est modifiée.

Les méthodes add_tick et remove_tick permettent à un développeur d'ajouter et de supprimer des méthodes qui écouteront l'événement tick. Ensuite, ces méthodes ajoutent ou suppriment le gestionnaire spécifié via la collection Sys.EventHandlerList du composant. L'objet EventHandlerList contient une collection de gestionnaires d'événements du composant via la propriété Sys.Component.events héritée. Dans l'exemple, le code appelle les méthodes Sys.EventHandlerList.addHandler et Sys.EventHandlerList.removeHandler de l'objet EventHandlerList retourné afin d'ajouter ou de supprimer le gestionnaire spécifié.

La classe Demo.Timer substitue la méthode dispose de la classe de base pour mettre à jour la propriété enabled et indiquer aux consommateurs que le composant a été désactivé. L'accesseur set de la propriété enabled déclenche l'événement propertyChanged pour envoyer la notification. Le code appelle la méthode private _stopTimer pour empêcher les événements tick d'être déclenchés. Enfin, le code appelle la méthode de base dispose pour permettre à l'application de libérer le composant.

Utilisation du composant Demo.Timer dans une page Web

Les instances de composants clients ASP.NET AJAX d'une page peuvent être gérées par un contrôle serveur personnalisé ou en utilisant le script client dans la page Web. De cette section, vous apprendrez comment créer une instance composant en utilisant le script client dans une page Web.

Pour créer une page utilisant le composant Demo.Timer

  1. Dans le répertoire où vous mettez le fichier DemoTimer.js, créez un fichier nommé DemoTimer.aspx et ajoutez-y le balisage et le code suivant :

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head >
            <title>Demo Timer Component</title>
    </head>
    <body>
        <form id="form1" > 
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                    <Scripts>
                        <asp:ScriptReference Path="DemoTimer.js"/>
                    </Scripts>
                </asp:ScriptManager>
    
                Timer Tick Count: <span id="result">0</span>
            </div>
    
            <script type="text/javascript">
    
                function OnTick(sender, args) {
                    var result = $get("result");
                    result.innerText = parseInt(result.innerText) + 1;
                }
    
                 var app = Sys.Application;
                 app.add_init(applicationInitHandler);
    
                 function applicationInitHandler(sender, args) {
                    // Create the DemoTimer component instance.  
                    // Set properties and bind events.
                    $create(Demo.Timer, 
                        {enabled:true,id:"demoTimer1",interval:2000}, 
                        {tick:OnTick}, null, null);
                }
    
            </script> 
        </form>
    </body>
    </html>
    
  2. Dans le même répertoire, créez un fichier nommé TestDemoTimer.js et ajoutez-y le code suivant :

    function OnTick(sender, args) {
        var result = $get("result");
        result.innerText = parseInt(result.innerText) + 1;
    }
    
     var app = Sys.Application;
     app.add_init(applicationInitHandler);
    
     function applicationInitHandler(sender, args) {
        // Create the DemoTimer component instance.  
        // Set properties and bind events.
        $create(Demo.Timer, 
            {enabled:true,id:"demoTimer1",interval:2000}, 
            {tick:OnTick}, null, null);
    }
    

Explication du code

La page d'exemple charge TestDemoTimer.js en utilisant du code JavaScript qui contient deux fonctions, OnTick et applicationInitHandler. La fonction OnTick gère l'événement tick du composant Demo.Timer et met à jour une valeur de compteur au sein d'un élément HTML span.

La fonction applicationInitHandler est un gestionnaire pour l'événement app_init. Dans la fonction, le composant Demo.Timer est instancié dans le script client en appelant la méthode $create et en passant les arguments suivants.

  • L'argument type est la classe Demo.Timer que vous avez créée précédemment.

  • L'argument properties se compose d'un objet JSON qui contient la valeur de l'ID de composant requis suivi par les paires nom/valeur de propriété qui spécifient des noms de propriété avec leurs valeurs initiales. À des fins de démonstration, la propriété interval a pour valeur initiale 2000 millisecondes afin que le temporisateur déclenche un événement tick toutes les 2 secondes. (Dans une application de production, vous définiriez probablement l'intervalle à une valeur supérieure pour réduire le trafic réseau.) La propriété enabled du composant a la valeur true afin que la minuterie démarre immédiatement après l'instanciation.

  • L'argument events contient un objet où des noms d'événements sont associés aux gestionnaires correspondants. Dans ce cas, le gestionnaire onTick est assigné à l'événement tick, défini dans l'élément script de la page.

Le fichier DemoTimer.aspx est une page Web ASP.NET qui héberge le composant. Dans le contrôle ScriptManager de la page, l'attribut path de l'élément asp:ScriptReference référence le chemin d'accès du fichier DemoTimer.js qui définit la classe de composant Demo.Timer.

Voir aussi

Tâches

Assignation dynamique de références de script

Concepts

Utilisation du contrôle UpdatePanel ASP.NET avec des contrôles liés aux données

Utilisation d'événements PageRequestManager

Référence

Sys.Component, classe

ScriptManager