Condividi tramite


Creazione di componenti client non visivi personalizzati

Aggiornamento: novembre 2007

In questo argomento viene illustrato come creare un componente client non visivo AJAX in ASP.NET che derivi dalla classe base Sys.Component del client e come utilizzare il componente in una pagina.

In questa esercitazione verrà illustrato come effettuare le seguenti attività:

  • Utilizzare il modello di progettazione prototipo in ECMAScript (JavaScript) per definire una classe di componente non visivo.

  • Registrare un componente non visivo come classe derivata dalla classe base Component.

  • Inizializzare la classe base Component del componente non visivo e richiamarne i metodi.

  • Creare proprietà che generino una notifica di modifica.

  • Utilizzare il componente in una pagina e eseguire l'associazione agli eventi del componente.

Nella panoramica viene riportato l'esempio di un timer come componente client non visivo. Il timer genera gli eventi che possono essere gestiti.

In questo argomento vengono illustrati gli oggetti basati sui componenti non visivi. Questi componenti derivano da Component e in genere non hanno una rappresentazione nell'interfaccia utente. Esistono due ulteriori tipi di oggetti del componente client ASP.NET AJAX che estendono la funzionalità del componente di base: i comportamenti che derivano da Sys.UI.Behavior e i controlli che derivano da Sys.UI.Control. Nella tabella riportata di seguito viene fornito un riepilogo delle differenze tra componenti, comportamenti e controlli.

Tipi di oggetti del componente client

Riepilogo

Componenti

  • Derivano dalla classe base Component.

  • In genere non dispongono di una rappresentazione nell'interfaccia utente, ad esempio un componente timer che genera eventi a intervalli ma non è visibile nella pagina.

  • Non dispongono di elementi DOM associati.

  • Incapsulano il codice client che deve essere riutilizzato tra le applicazioni.

Comportamenti

  • Derivano dalla classe base Behavior, che estende la classe base Component.

  • Estendono il comportamento degli elementi DOM, ad esempio il comportamento di un watermarking da associare a una casella di testo esistente.

  • Possono creare elementi dell'interfaccia utente, anche se in genere non modificano il comportamento di base dell'elemento DOM a cui sono associati.

  • È possibile accedervi direttamente dall'elemento DOM tramite un attributo personalizzato (expando). L'attributo presenterà il nome del comportamento se ne è stato impostato uno. In caso contrario, presenterà il nome del tipo (non completo).

  • Non richiedono l'associazione con un altro oggetto client, ad esempio una classe derivata dalle classi Control o Behavior.

  • Possono fare riferimento a un controllo o a un elemento HTML diverso da un controllo nella relativa proprietà element.

Controlli

  • Derivano dalla classe base Control che estende la classe base Component.

  • Rappresentano un elemento DOM come oggetto client, modificando in genere il comportamento normale dell'elemento DOM originale per fornire nuove funzionalità. Ad esempio, un controllo menu potrebbe leggere gli elementi li da un elemento ul come dati di origine, ma non visualizzare un elenco puntato.

  • È possibile accedervi direttamente dall'elemento DOM tramite il controllo expando.

Prerequisiti

Per eseguire l'esempio citato in questo argomento, è necessario disporre dei seguenti elementi:

Creazione di funzionalità di base di un componente client non visivo

Un componente client non visivo ASP.NET AJAX incapsula il codice JavaScript che deve essere riutilizzato tra le applicazioni. Un esempio di componente non visivo è il componente timer che genera eventi a intervalli fissi.

Poiché deriva dalla classe base Component, il componente personalizzato eredita automaticamente le funzionalità seguenti:

  • Un modello per più browser per la gestione delle associazioni del gestore agli eventi dell'oggetto client.

  • La registrazione automatica del componente nell'applicazione client come oggetto eliminabile che implementa l'interfaccia Sys.IDisposable.

  • La possibilità di generare eventi di notifica quando le proprietà vengono modificate.

  • La possibilità di eseguire l'elaborazione batch delle impostazioni delle proprietà di un componente. È più efficace in termini di dimensione dello script e tempo di elaborazione rispetto alla gestione della logica nelle funzioni di accesso get e set per una singola proprietà.

  • L'override del metodo Sys.UI.Component.initialize per inizializzare le proprietà e i listener di eventi.

Implementazione di un componente client derivato dalla classe Component

Per implementare un componente client personalizzato derivato da Component, è necessario seguire questi passaggi:

  • Definire la classe di un componente utilizzando il modello di progettazione prototipo.

  • Inizializzare l'istanza di base Component del componente.

  • Esporre una funzione di accesso della proprietà e facoltativamente generare un evento di notifica propertyChanged.

  • Eseguire l'override del metodo dispose per rilasciare le risorse, ad esempio rimuovendo i gestori eventi.

Nelle sezioni seguenti vengono fornite ulteriori informazioni sui passaggi di implementazione.

Definizione della classe di un componente utilizzando il modello di progettazione prototipo

Una classe client ASP.NET AJAX che includa una classe di componente viene definita in JavaScript utilizzando il modello di progettazione prototipo. Per definire la classe di un componente utilizzando il modello di progettazione prototipo, attenersi alla seguente procedura:

  • Registrare lo spazio dei nomi per la classe di componente.

  • Creare la funzione del costruttore del componente e definire nella funzione del costruttore i campi privati impostandone i valori iniziali.

  • Definire il prototipo del componente.

  • Registrare la funzione del componente come classe derivata da Component.

Per ulteriori informazioni, vedere Creazione di una classe Component del client tramite il modello di prototipo.

Inizializzazione della classe base

Nella funzione del costruttore del componente, si richiama il metodo Type.initializeBase ereditato per inizializzare il tipo di base della classe registrata. Una classe del componente non visiva viene registrata come una classe che ha il tipo di base Component. Quando la classe base Component viene inizializzata, i relativi metodi diventano disponibili per il componente e viene automaticamente registrata come oggetto eliminabile con l'applicazione ASP.NET con supporto AJAX. Per ulteriori informazioni, vedere Interfaccia Sys.IDisposable.

Qualsiasi classe del componente che derivi da Component deve inizializzare la sua classe base dal costruttore. In genere, initializeBase viene richiamato prima che nel costruttore venga eseguito qualsiasi altro codice. Nell'esempio seguente viene illustrata la funzione del costruttore di un componente non visivo che derivi da Component.

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

Definizione delle proprietà e generazione di notifiche in caso di modifica delle proprietà

Le proprietà vengono definite nella classe del componente che gli sviluppatori di pagine possono ottenere e impostare. Un componente ASP.NET AJAX che deriva da Component eredita il metodo Sys.Component.raisePropertyChanged che viene chiamato per generare un evento propertyChanged per le proprietà del componente. Gli sviluppatori di pagine che utilizzano il componente possono quindi eseguire l'associazione a questi eventi. Per ulteriori informazioni, vedere Definizione di proprietà del componente personalizzato e generazione di eventi PropertyChanged.

Inizializzazione di proprietà e listener di eventi

Se è necessario inizializzare proprietà o listener di eventi per il componente personalizzato, eseguire l'override del metodo Sys.Component.initialize nel prototipo del componente. Un componente non visivo che deriva da Component potrebbe assegnare un delegato a un evento, ad esempio window.onFocus. Come ultimo passaggio, chiamare il metodo di base initialize per consentire alla classe base del componente di completare l'inizializzazione.

ASP.NET fornisce le classi e i metodi che offrono la gestione degli eventi standard per i componenti e gli elementi DOM. Per gestire gli eventi del componente, utilizzare la classe Sys.EventHandlerList. Ad esempio, associare eventi utilizzando il metodo Sys.EventHandlerList.addHandler e rilasciarli utilizzando il metodo Sys.EventHandlerList.removeHandler. Per ulteriori informazioni, vedere la classe Classe Sys.EventHandlerList.

Per gestire i gestori eventi per gli elementi DOM o per l'oggetto window, utilizzare la classe Sys.UI.DomEvent. Ad esempio, è possibile associare e separare i gestori eventi utilizzando i metodi Sys.UI.DomEvent addHandler e Sys.UI.DomEvent removeHandler. Per ulteriori informazioni, vedere la classe Classe Sys.UI.DomEvent.

Rilascio delle risorse

Se è necessario rilasciare le risorse per il componente personalizzato prima dell'eliminazione del componente, eseguire l'override del metodo dispose e rilasciare le risorse nel metodo sottoposto a override. In questo modo le risorse vengono rilasciate immediatamente prima dell'eliminazione del componente. Le risorse che devono essere rilasciate potrebbero includere gestori per gli eventi DOM. Verificare che siano stati eliminati tutti i possibili riferimenti circolari tra gli elementi DOM e l'oggetto del componente in modo da poter rimuovere l'oggetto dalla memoria. Per ulteriori informazioni, vedere Rilascio delle risorse del componente.

Utilizzo di un componente non visivo in una pagina

Per utilizzare un componente client personalizzato in una pagina dell'applicazione ASP.NET AJAX, procedere come indicato di seguito.

  • Registrare la libreria di script del componente nella pagina Web.

  • Creare un'istanza del componente.

Nelle sezioni seguenti vengono fornite ulteriori informazioni su questo passaggi.

Registrazione di una libreria di script del componente nella pagina Web

È possibile registrare gli script necessari per un controllo client nella pagina con un controllo ScriptManager, sia in modo dichiarativo che a livello di codice. Nell'esempio seguente viene illustrato il markup dichiarativo per un controllo ScriptManager che registra lo script di un componente.

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

L'elemento asp:ScriptManager contiene un elemento asp:ScriptReference all'interno di un nodo scripts. L'attributo path dell'elemento asp:ScriptReference fa riferimento al percorso del file js, nell'esempio DemoTimer.js, che definisce la classe di un componente. Per ulteriori informazioni, vedere Assegnazione dinamica dei riferimenti a uno script e i cenni preliminari sulla classe ScriptManager.

Invece di registrare i file script mediante il controllo ScriptManager, è possibile gestire i componenti client utilizzando un controllo server personalizzato che implementi l'interfaccia IScriptControl. Un controllo server personalizzato può registrare automaticamente gli script del componente necessari ed esporre il markup dichiarativo per l'impostazione delle proprietà e delle associazioni eventi del componente. Se si utilizza un controllo server personalizzato per registrare gli script, lo sviluppatore di pagine utilizza il componente con più facilità. Per ulteriori informazioni, vedere i cenni preliminari sulla classe IScriptControl.

Nota:

Tutti i file script autonomi che vengono registrati con il controllo ScriptManager devono chiamare il metodo notifyScriptLoaded per notificare all'applicazione la fine del caricamento dello script. Nella maggior parte dei casi, gli script incorporati in un assembly non devono chiamare questo metodo. Per ulteriori informazioni, vedere la classe Metodo Sys.Application.notifyScriptLoaded.

Creazione di un'istanza di un componente personalizzato

L'istanza di un componente client viene creata chiamando il metodo Sys.Component.create o il collegamento $create. Per specificare il tipo di componente, i parametri vengono passati al metodo $create. Viene passato anche un oggetto JSON contenente un valore ID obbligatorio e i valori della proprietà iniziali e facoltativi e le associazioni facoltative del gestore eventi.

Nell'esempio seguente viene illustrato come creare l'istanza di un componente chiamando il metodo $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);
}

Per ulteriori informazioni, vedere°Metodo Sys.Component.create e Metodo $create di Sys.Component.

Creazione del componente Demo.Timer personalizzato

In questa sezione, verrà creato un componente client personalizzato denominato Demo.Timer che estende la classe base Component e quindi si utilizzerà il componente in una pagina. Demo.Timer è un semplice componente timer che definisce l'evento tick, espone le proprietà enabled e interval e genera un evento di notifica della modifica per la proprietà interval. Lo sviluppatore di pagine che utilizza il componente Demo.Timer può gestire l'evento tick. Inoltre, può eseguire associazioni all'evento modificato dalla proprietà e intraprendere azioni ogni volta che la proprietà interval viene aggiornata.

Per creare il codice per il componente Demo.Timer

  1. Nella directory radice di un'applicazione Web ASP.NET con supporto AJAX, creare un file denominato DemoTimer.js.

  2. Aggiungere al file il codice riportato di seguito:

    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();
    
    

Illustrazione del codice

Il codice registra lo spazio dei nomi Demo chiamando il metodo Type.registerNamespace. Si consiglia di dichiarare e inizializzare tutti i campi privati nel costruttore, ad esempio interval in questo esempio. Il costruttore richiama il metodo initializeBase ereditato in modo da rendere disponibili i metodi della classe base Component. La classe base inizializzata registra a sua volta l'istanza Demo.Timer con l'applicazione client come oggetto eliminabile.

Nel prototipo il codice dichiara e inizializza le due proprietà pubbliche interval e enabled. Le definizioni di proprietà includono i campi privati per conservare i valori e le funzioni di accesso get e set per ciascuna proprietà. Nel metodo della funzione di accesso set per ogni proprietà pubblica, il codice genera l'evento propertyChanged richiamando il metodo raisePropertyChanged. Questo evento notifica agli sviluppatori di pagine ogni modifica apportata alla proprietà.

I metodi add_tick e remove_tick consentono allo sviluppatore di pagine di aggiungere e rimuovere i metodi che ascolteranno l'evento tick. Questi metodi a loro volta aggiungono o rimuovono il gestore specificato tramite l'insieme Sys.EventHandlerList del componente. L'oggetto EventHandlerList contiene un insieme dei gestori eventi del componente tramite la proprietà Sys.Component.events ereditata. Nell'esempio il codice richiama i metodi Sys.EventHandlerList.addHandler e Sys.EventHandlerList.removeHandler dell'oggetto EventHandlerList restituito per aggiungere o rimuovere il gestore specificato.

La classe Demo.Timer esegue l'override del metodo dispose della classe base per aggiornare la proprietà enabled e indicare agli utenti che il componente è stato disattivato. La funzione di accesso set per la proprietà enabled genera l'evento propertyChanged per inviare la notifica. Il codice richiama il metodo _stopTimer privato per arrestare la generazione degli eventi tick. Infine, il codice chiama il metodo dispose di base per consentire all'applicazione di rilasciare il componente.

Utilizzo del componente Demo.Timer in una pagina Web

Le istanze dei componenti client ASP.NET AJAX in una pagina possono essere gestite da un controllo server personalizzato o utilizzando uno script client nella pagina Web. In questa sezione viene illustrato come creare l'istanza di un componente utilizzando uno script client in una pagina Web.

Per creare una pagina per il componente Demo.Timer

  1. Nella directory dove si trova il file DemoTimer.js, creare un file denominato DemoTimer.aspx e aggiungervi il markup e il codice seguenti:

    <!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. Nella stessa directory, creare un file denominato TestDemoTimer.js e aggiungervi il codice seguente:

    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);
    }
    

Illustrazione del codice

La pagina di esempio carica TestDemoTimer.js utilizzando codice JavaScript che contiene due funzioni, OnTick e applicationInitHandler. La funzione OnTick gestisce l'evento tick del componente Demo.Timer e aggiorna il valore di un contatore in un elemento HTML span.

La funzione applicationInitHandler è un gestore per l'evento app_init. Nella funzione viene creata l'istanza del componente Demo.Timer in uno script client richiamando il metodo $create, tramite gli argomenti seguenti:

  • L'argomento type è la classe Demo.Timer creata precedentemente.

  • L'argomento properties è costituito da un oggetto JSON contenente il valore ID del componente obbligatorio, seguito dalle coppie nome/valore delle proprietà che specificano i nomi delle proprietà con i valori iniziali. La proprietà interval è impostata inizialmente a mero scopo esemplificativo, su 2000 millisecondi così che il timer genererà l'evento tick ogni 2 secondi. In un'applicazione di produzione, probabilmente si imposterebbe l'intervallo su un più grande valore per ridurre traffico di rete. La proprietà enabled del componente è impostata su true così che il timer si avvierà immediatamente dopo la creazione dell'istanza.

  • L'argomento events contiene un oggetto con le coppie nome evento/gestore. In questo caso, il gestore onTick è assegnato all'evento tick definito nell'elemento script della pagina.

Il file DemoTimer.aspx è una pagina Web ASP.NET contenente il componente. Nel controllo ScriptManager della pagina, l'attributo path dell'elemento asp:ScriptReference fa riferimento al percorso del file DemoTimer.js che definisce la classe del componente Demo.Timer.

Vedere anche

Attività

Assegnazione dinamica dei riferimenti a uno script

Concetti

Utilizzo del controllo UpdatePanel ASP.NET con più controlli con associazione a dati

Utilizzo di eventi PageRequestManager

Riferimenti

Classe Sys.Component

ScriptManager