Compartir a través de


Crear componentes de cliente no visuales personalizados

Actualización: noviembre 2007

En este tema se explica cómo crear un componente cliente AJAX no visual en ASP.NET derivado de la clase base Sys.Component del cliente y cómo utilizar el componente en una página.

En este tutorial, aprenderá a hacer lo siguiente:

  • Usar el modelo de diseño de prototipos para definir una clase de componente no visual en ECMAScript (JavaScript).

  • Registrar un componente no visual como una clase derivada de la clase base Component.

  • Inicializar la clase base Component del componente no visual e invocar sus métodos.

  • Crear propiedades que generen una notificación de cambios.

  • Usar el componente en una página y enlazar a los eventos del componente.

En la descripción general se proporciona un ejemplo de un temporizador como un componente cliente no visual. El temporizador provoca eventos que puede controlar.

Este tema se centra en objetos basados en componentes cliente no visuales. Estos componentes se derivan de Component y normalmente no tienen una representación de interfaz de usuario. Hay dos tipos adicionales de objetos de componente cliente AJAX de ASP.NET que extienden la funcionalidad del componente básico: los comportamientos que se derivan de Sys.UI.Behavior y los controles que se derivan de Sys.UI.Control. En la tabla siguiente se indican las diferencias entre los componentes, los comportamientos y los controles.

Tipos de objeto de componente cliente

Resumen

Componentes

  • Se derivan de la clase base Component.

  • Normalmente, no tienen ninguna representación de interfaz de usuario, como un componente de temporizador que provoca eventos a intervalos pero no está visible en la página.

  • No tienen ningún elemento DOM asociado.

  • Encapsulan código cliente diseñado para que se pueda volver a utilizar en otras aplicaciones.

Comportamientos

  • Se derivan de la clase base Behavior, que extiende la clase base Component.

  • Extienden el comportamiento de los elementos DOM, como el comportamiento de impresión de marcas de agua que puede asociarse a un cuadro de texto existente.

  • Pueden crear elementos de la interfaz de usuario, aunque normalmente no modifican el funcionamiento básico del elemento DOM al que están asociados.

  • Se puede obtener acceso directamente del elemento de DOM a través de un atributo personalizado (expando). El atributo tendrá el nombre del comportamiento si se estableció uno; de lo contrario, tendrá el nombre del tipo (no completo).

  • No requieren una asociación con otro objeto cliente, como una clase derivada de las clases Control o Behavior.

  • Pueden hacer referencia a un control o a un elemento HTML que no sea un control en su propiedad element.

Controles

  • Se derivan de la clase base Control, que extiende la clase base Component.

  • Representan un elemento DOM como un objeto cliente, cambiando normalmente el comportamiento habitual del elemento DOM original para proporcionar la nueva funcionalidad. Por ejemplo, un control de menú podría leer los elementos li de un elemento ul como sus datos de origen, pero no mostrar una lista con viñetas.

  • Se obtiene acceso directamente a ellos desde el elemento DOM a través del expando del control.

Requisitos previos

Para ejecutar el ejemplo de este tema, necesitará:

Crear la funcionalidad básica de un componente cliente no visual

Un componente cliente AJAX no visual de ASP.NET encapsula código JavaScript diseñado para que se puede utilizar en otras aplicaciones. Un ejemplo de un componente no visual es un componente de temporizador que provoca eventos a intervalos fijos.

Al derivarse de la clase base Component, el componente personalizado hereda automáticamente las características siguientes:

  • Un modelo apto para su uso en distintos exploradores para administrar los enlaces de controlador a eventos de objetos cliente.

  • El registro automático del componente en la aplicación cliente como un objeto descartable que implementa la interfaz Sys.IDisposable.

  • Capacidad para provocar eventos de notificación cuando se cambian las propiedades.

  • Capacidad para realizar procesamiento por lotes de los valores de propiedad del componente. Esto es más eficaz en cuanto a tamaño del script y tiempo de proceso que administrar toda la lógica en los descriptores de acceso get y set de cada propiedad.

  • Invalidación del método Sys.Component.initialize para inicializar las propiedades y los agentes de escucha de eventos.

Implementar un componente cliente derivado de la clase Component

Para implementar un componente cliente personalizado derivado de Component, realice este procedimiento:

  • Defina una clase de componente mediante el modelo de diseño de prototipos.

  • Inicialice la instancia base Component del componente.

  • Exponga los descriptores de acceso de propiedad y, de manera opcional, provoque un evento de notificación propertyChanged.

  • Invalide el método dispose para liberar recursos, como borrar los controladores de eventos.

En las secciones siguientes se proporciona información detallada acerca de los pasos de implementación.

Definir una clase Component mediante el modelo de diseño de prototipos

Una clase de cliente AJAX de ASP.NET, que incluye una clase de componente, se define en JavaScript utilizando el modelo de diseño de prototipos. Para definir una clase de componente mediante el modelo de diseño de prototipos, debe realizar el siguiente procedimiento:

  • Registre el espacio de nombres de su clase de componente.

  • Cree la función del constructor del componente y, en ella, defina todos los campos privados y establezca sus valores iniciales.

  • Defina el prototipo del componente.

  • Registre la función de componente como una clase derivada de Component.

Para obtener más información, vea Crear una clase de componente de cliente utilizando el modelo de prototipo.

Inicializar la clase base

En la función de constructor del componente, invoque el método Type.initializeBase heredado para inicializar el tipo base de su clase registrada. Una clase de componente no visual se registra como una clase con un tipo base de Component. Cuando se inicializa la clase base Component, sus métodos están disponibles para el componente y el componente se registra automáticamente como un objeto descartable con la aplicación ASP.NET habilitada para AJAX. Para obtener más información, vea Sys.IDisposable (Interfaz).

Cualquier clase de componente derivada de Component debe inicializar su clase base desde el constructor. Normalmente, el método initializeBase se invoca antes de que se ejecute cualquier otro código en el constructor. En el ejemplo siguiente se muestra la función de constructor de un componente no visual derivado de Component.

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

Definir propiedades y generar notificaciones de cambio de propiedades

En la clase del componente se definen propiedades que los desarrolladores de páginas pueden obtener y establecer. Un componente AJAX de ASP.NET derivado de Component hereda el método Sys.Component.raisePropertyChanged, al que se llama para provocar un evento propertyChanged para las propiedades del componente. Los desarrolladores de páginas que utilicen su componente pueden enlazar a estos eventos. Para obtener más información, vea Definir propiedades de componentes personalizados y provocar eventos PropertyChanged.

Inicializar propiedades y agentes de escucha de eventos

Si su componente personalizado debe inicializar propiedades o agentes de escucha de eventos, debe invalidar el método Sys.Component.initialize en el prototipo del componente. Por ejemplo, un componente no visual derivado de Component podría asignar un delegado a un evento como window.onFocus. Como paso final, se llama al método initialize base para que la clase base del componente pueda completar la inicialización.

ASP.NET proporciona clases y métodos que permiten administrar eventos estándar para componentes y elementos DOM. Para administrar los eventos del componente, utilice la clase Sys.EventHandlerList. Por ejemplo, enlace los eventos mediante el método Sys.EventHandlerList.addHandler y libérelos mediante el método Sys.EventHandlerList.removeHandler. Para obtener más información, vea Sys.EventHandlerList (Clase).

Para administrar los controladores de eventos de elementos DOM o del objeto window, utilice la clase Sys.UI.DomEvent. Por ejemplo, puede enlazar y desenlazar controladores de eventos mediante los métodos Sys.UI.DomEvent addHandler y Sys.UI.DomEvent removeHandler. Para obtener más información, vea Sys.UI.DomEvent (Clase).

Liberar recursos

Si el componente personalizado debe liberar recursos antes de eliminar el componente, invalide el método dispose y libere los recursos del método invalidado. De esta forma, se asegurará de que se liberan los recursos inmediatamente antes de descartar el componente. Entre los recursos que se deben liberar se incluyen los controladores de los eventos DOM. Compruebe que se han quitado las posibles referencias circulares entre los elementos DOM y el objeto de componente para asegurarse de que el objeto se puede quitar de la memoria. Para obtener más información, vea Liberar recursos de componente.

Utilizar un componente no visual en una página

Para utilizar un componente cliente personalizado en una página de aplicación AJAX de ASP.NET, siga este procedimiento:

  • Registre la biblioteca de scripts del componente en la página web.

  • Cree una instancia del componente.

En las secciones siguientes se proporcionan detalles sobre estos pasos.

Registrar la biblioteca de scripts del componente en la página web

Puede registrar los scripts necesarios para un control de cliente en la página con un control ScriptManager, mediante declaración o mediante programación. En el ejemplo siguiente se muestra el marcado declarativo para un control ScriptManager que registra un script de componente.

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

El elemento asp:ScriptManager contiene un elemento asp:ScriptReference dentro de un nodo scripts. El atributo path del elemento asp:ScriptReference hace referencia a la ruta de acceso del archivo .js (en el ejemplo, DemoTimer.js) que define una clase de componente. Para obtener más información, vea Asignar referencias de script de forma dinámica y la información general de la clase ScriptManager.

Como alternativa al registro de archivos de script mediante el control ScriptManager, puede administrar los componentes cliente utilizando un control de servidor personalizado que implemente la interfaz IScriptControl. El control de servidor personalizado puede registrar automáticamente los scripts de componente necesarios y exponer el marcado declarativo para establecer las propiedades del componente y los enlaces de eventos. Si registra los scripts mediante un control de servidor personalizado, puede simplificar el uso del componente por parte de un desarrollador de páginas. Para obtener más información, vea la introducción a la clase IScriptControl.

Nota:

Todos los archivos de script independientes que se van a registrar con el control ScriptManager deben llamar al método notifyScriptLoaded para notificar a la aplicación que el script ha terminado de cargarse. Los scripts incrustados en un ensamblado no deben llamar a este método en la mayoría de los casos. Para obtener más información, vea Sys.Application.notifyScriptLoaded (Método).

Crear una instancia de un componente personalizado

Las instancia de un componente cliente se crea llamando al método Sys.Component.create o al método abreviado $create. Se pasan parámetros al método $create para especificar el tipo de componente. Se pasa también un objeto JSON que contiene un valor de identificador necesario y valores de propiedad iniciales opcionales, así como enlaces de controlador de eventos opcionales.

En el ejemplo siguiente se muestra cómo crear instancias de un componente mediante una llamada al método $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);
}

Para obtener más información, vea Sys.Component.create (Método) y Sys.Component $create (Método).

Crear el componente Demo.Timer personalizado

En esta sección, creará un componente cliente personalizado denominado Demo.Timer que extiende la clase base Component y, a continuación, utilizará el componente en una página. Demo.Timer es un componente de temporizador simple que define un evento tick, expone una propiedad enabled y una propiedad, interval y provoca un evento de notificación de cambios para la propiedad interval. Un desarrollador de páginas que utilice el componente Demo.Timer podrá controlar el evento tick. El programador puede enlazar también al evento de cambio de propiedad y realizar una acción cada vez que se actualice la propiedad interval.

Para crear el código para el componente Demo.Timer

  1. En el directorio raíz de una aplicación web ASP.NET habilitada para AJAX, cree un archivo denominado DemoTimer.js.

  2. Agregue el código siguiente al archivo:

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

Descripción del código

El código registra el espacio de nombres Demo mediante una llamada al método Type.registerNamespace. Es recomendable que declare e inicialice todos los campos privados en el constructor, como interval en este ejemplo. El constructor invoca el método initializeBase heredado para que los métodos de la clase base Component estén disponibles. A su vez, la clase base inicializada registra la instancia de Demo.Timer en la aplicación cliente como un objeto descartable.

En el prototipo, el código declara e inicializa dos propiedades públicas: interval y enabled. Las definiciones de propiedad incluyen los campos privados que contienen sus valores y los descriptores de acceso get y set de cada propiedad. En el método de descriptor de acceso set de cada propiedad pública, el código provoca un evento propertyChanged invocando el método raisePropertyChanged. Este evento informa a los desarrolladores de páginas cada vez que cambia la propiedad.

Los métodos remove_tick y add_tick permiten que el desarrollador de páginas agregue y quite métodos que realizan escuchas para el evento tick. A su vez, estos métodos agregan o quitan el controlador especificado a través de la colección Sys.EventHandlerList del componente. El objeto EventHandlerList contiene una colección de los controladores de eventos del componente mediante la propiedad heredada Sys.Component.events. En el ejemplo, el código invoca los métodos Sys.EventHandlerList.addHandler y Sys.EventHandlerList.removeHandler del objeto EventHandlerList devuelto para agregar o quitar el controlador especificado.

La clase Demo.Timer invalida el método de la clase base dispose para actualizar la propiedad enabled e indicar a los consumidores que el componente se ha deshabilitado. El descriptor de acceso set de la propiedad enabled provoca el evento propertyChanged para enviar la notificación. El código invoca el método _stopTimer privado para evitar que se provoquen los eventos tick. Por último, el código llama al método dispose base para que la aplicación pueda liberar el componente.

Utilizar el componente Demo.Timer en un página web

Las instancias de componentes cliente AJAX de ASP.NET en una página se pueden administrar mediante un control de servidor personalizado o utilizando el script de cliente en la página web. En esta sección, aprenderá a crear una instancia de componente mediante un script de cliente en una página web.

Para crear una página que utilice el componente Demo.Timer

  1. En el directorio en el que se encuentra el archivo DemoTimer.js, cree un archivo denominado DemoTimer.aspx y agréguele el marcado y código siguientes:

    <!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. En el mismo directorio, cree un archivo denominado TestDemoTimer.js y agréguele el siguiente código:

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

Descripción del código

La página de ejemplo carga TestDemoTimer.js utilizando código JavaScript que contiene dos funciones, OnTick y applicationInitHandler. La función OnTick controla el evento tick del componente Demo.Timer y actualiza el valor de un contador en un elemento HTML span.

La función applicationInitHandler es un controlador del evento app_init. En la función, la instancia del componente Demo.Timer se crea en el script de cliente invocando el método $create, con los argumentos siguientes:

  • El argumento type es la clase Demo.Timer que creó anteriormente.

  • El argumento properties consta de un objeto JSON que contiene el valor de identificador de componente necesario, seguido por los pares nombre-valor de propiedad que especifican los nombres de propiedad y sus valores iniciales. A efectos ilustrativos, la propiedad interval está establecida inicialmente en 2.000 milisegundos para que el temporizador provoque un evento tick cada dos segundos. (En una aplicación en producción, establecería probablemente el intervalo en un valor mayor para reducir el tráfico de red). La propiedad enabled del componente está establecida en true para que el temporizador se inicie en cuanto se haya creado su instancia.

  • El argumento events contiene un objeto con los nombres de evento emparejados con sus controladores. En este caso, el controlador onTick está asignado al evento tick, que se define en el elemento script de la página.

El archivo DemoTimer.aspx es una página web ASP.NET que hospeda el componente. En el control ScriptManager de la página, el atributo path del elemento asp:ScriptReference hace referencia a la ruta de acceso del archivo DemoTimer.js que define la clase de componente Demo.Timer.

Vea también

Tareas

Asignar referencias de script de forma dinámica

Conceptos

Usar el control UpdatePanel de ASP.NET con controles enlazados a datos

Trabajar con eventos de PageRequestManager

Referencia

Sys.Component (Clase)

ScriptManager