Compartir a través de


Crear eventos de cliente personalizados

Actualización: noviembre 2007

La funcionalidad de AJAX en ASP.NET incluye un completo modelo de eventos de cliente de varias capas. La clase Sys.Application proporciona eventos en el nivel de aplicación. La clase Sys.WebForms.PageRequestManager proporciona eventos que pertenecen a las partes de la página implicadas en la representación parcial de páginas. Los componentes individuales, como controles y comportamientos, tienen sus propios eventos. Para obtener más información sobre estos eventos, vea Eventos de ciclo de vida de cliente de AJAX.

ASP.NET también permite agregar eventos al ciclo de vida del cliente. La clase Sys.UI.DomEvent permite enlazar los eventos del modelo de objetos de documento (DOM) HTML a los componentes AJAX de ASP.NET personalizados. Además, la clase Sys.EventHandlerList permite crear directamente nuevos eventos de cliente AJAX de ASP.NET.

Asociar a eventos DOM

En muchos casos, un evento con el que desea trabajar corresponde a un evento definido en el DOM HTML. Por ejemplo, un control de botón AJAX de ASP.NET personalizado puede usar el evento click del elemento <button> de HTML al que está asociado. Para enlazar un evento basado en DOM a una aplicación o un componente personalizado AJAX de ASP.NET, se usa el método addHandler de la clase DomEvent, como se muestra en el ejemplo siguiente:

Sys.UI.DomEvent.addHandler(element, 'click', this.myClickHandler);

También puede usar el acceso directo $addHandlercomo se muestra en el ejemplo siguiente:

$addHandler(element, 'click', this.myClickHandler);

El método addHandler incluye tres parámetros, element, eventName y handler. El parámetro element es una referencia al elemento DOM que expone el evento. El parámetro eventName es el nombre del propio evento DOM. El parámetro handler es una referencia a la función que se llama cuando se provoca el evento. Para obtener más información, vea Sys.UI.DomEvent addHandler (Método).

Para quitar un controlador de un evento DOM, se llama al método Sys.UI.DomEvent.removeHandler o al acceso directo $removeHandler, pasando los mismos parámetros que se pasan a addHandler.

Nota:

Los nombres de evento pasados a las funciones removeHandler y addHandler no deben incluir el prefijo "on". Por ejemplo, use "click", no "onclick".

Agregar y quitar controladores de eventos personalizados

Para agregar un nuevo controlador de eventos en un evento de un componente AJAX de ASP.NET personalizado, use el método addHandler de la clase Sys.EventHandlerList. Todos los eventos de cliente y los controladores de eventos asociados del modelo de eventos AJAX de ASP.NET se almacenan en un objeto EventHandlerList, un diccionario especializado con este fin. Cada componente, incluido el objeto Application actual, tiene su propia instancia EventHandlerList. Si agrega un elemento al objeto EventHandlerList, agrega un nuevo evento y un controlador de eventos al componente asociado. Para agregar eventos, use la sintaxis siguiente:

this.get_events().addHandler(event, handler);

La propiedad events de la clase Sys.Component devuelve la instancia EventHandlerList de dicho componente. Las clases Sys.UI.Control, Sys.UI.Behavior y Sys.Application heredan la propiedad events. El parámetro de event es el nombre del evento nuevo o existente para el que se agrega un controlador. El parámetro handler es una referencia a la función que se llama cuando se provoca el evento. Si establece el parámetro de event en un nuevo valor, agrega un nuevo evento al diccionario.

Para quitar un evento personalizado del diccionario, se usa el método removeHandler de la clase Sys.EventHandlerList, que toma los mismos parámetros que addHandler.

Para agregar controladores a los eventos que ya están definidos en Microsoft AJAX Library, use el descriptor de acceso add_ para ese evento, como en el ejemplo siguiente:

Sys.Application.add_load(myLoadHandler);

Provocar eventos personalizados

Para provocar un evento personalizado, llame al método getHandler de la instancia EventHandlerList, pasando el nombre del evento como parámetro. Este método devuelve una función que agrega todas las funciones que son controladores de dicho evento. Llame a la función devuelta para provocar el evento, como en el ejemplo siguiente:

var h = this.get_events().getHandler('myCustomEvent')
if (h) h(this, Sys.EventArgs.Empty);

Por convención, los controladores de eventos utilizan dos parámetros: sender y eventArgs. El remitente es el componente al que se aplica el evento, normalmente this. El parámetro eventArgs hace referencia a un objeto Sys.EventArgs. Este objeto puede contener información pasada al evento, como coordenadas del mouse. Puede omitir los parámetros eventArgs y sender, siempre que la firma de la función devuelta por getHandler coincida con todas las funciones de controlador asociadas. Sin embargo, la práctica recomendado incluye los parámetros, como en el ejemplo mostrado anteriormente.

Ejemplo

Descripción

El ejemplo siguiente crea una sencilla prueba de opción múltiple con dos secciones. Cuando se responden todas las preguntas de una sección, cambia el color de fondo de la sección. Cuando el usuario hace clic en el botón al final de la prueba, un mensaje de estado situado al lado de cada pregunta muestra si la respuesta es correcta.

La aplicación incluye instancias de dos controles personalizados. El control Question se asocia a un elemento <select> de HTML y el control Section se asocia a un elemento <div> que contiene uno o más controles Question. El control Question expone un evento select, que se enlaza al evento onChange del elemento <select> subyacente mediante una instancia Sys.UI.DomEvent. El control Section expone un evento complete, que es provocado por una función definida por el usuario cuando se ha respondido a todos los controles Question de la instancia Section.

Código

El ejemplo siguiente muestra la página Default.aspx que crea las instancias de componente y administra los eventos.

<%@ Page Language="VB" %>

<!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 id="Head1" >
    <title>Custom Events Example</title>
</head>
<body>
<form id="form1" >
    <asp:ScriptManager ID="ScriptManager1"  >
        <Scripts>
           <asp:ScriptReference Path="question.js" />
           <asp:ScriptReference Path="section.js" />
       </Scripts>
    </asp:ScriptManager>
    <script type="text/javascript">
    // Add handler to init event
    Sys.Application.add_init(appInitHandler);

    function appInitHandler() {
      // create components
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question1'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question2'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question3'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question4'));
      $create(Demo.Section, null,
        {complete: onSectionComplete},null, $get('group1'));
      $create(Demo.Section, null,
        {complete: onSectionComplete},null, $get('group2'));
    }

    function onAnswer(question) {
        // If all questions in this section answered, 
        // raise complete event
        var section = question.get_element().parentElement;
        var questions = section.children;
        $get(question.get_id() + 'Status').innerHTML = '';
        for (var i=0; i<questions.length; i++) {
            if (questions[i].selectedIndex === -1) {
                return;
            }
        }
        $find(section.id).raiseComplete();
    }

    function onSectionComplete(section) {
        // Change background color of <div>.
        section.get_element().style.backgroundColor = 'yellow';
    }

    function done() {
        // Display correct answers where needed.
        var c = Sys.Application.getComponents();
        for (var i=0; i<c.length; i++) {
            var type = Object.getType(c[i]).getName();
            if (type !== 'Demo.Question') continue;
            var element = c[i].get_element();
            var answer = element.selectedIndex;
            var correct = $find(c[i].get_id()).get_correct();
            var statusElement = c[i].get_id() + 'Status';
            if (answer !== correct) {
                $get(statusElement).innerHTML = 'Incorrect. Try again.';
            }
            else
            {
                $get(statusElement).innerHTML = 'Correct.';
            }
        }
    }

    function resethandler() {
        var c = Sys.Application.getComponents();
        for (var i=0; i<c.length; i++) {
            var type = Object.getType(c[i]).getName();
            if (type === 'Demo.Question') {
                var element = c[i].get_element();
                element.selectedIndex = -1;
                var answer = element.selectedIndex;
                var statusElement = c[i].get_id() + 'Status';
                $get(statusElement).innerHTML = '';
            }
            else if (type === 'Demo.Section') {
                c[i].get_element().style.backgroundColor = 'White';

            }
        }
    }
    </script>
    <h3>Addition</h3><br />
    <div id="Group1">
        2 + 2 = 
        <select id="Question1">
            <option>2</option>
            <option>22</option>
            <option>4</option>
            <option>5</option>
        </select><span id="Question1Status"></span><br />
        2 + 3 = 
        <select id="Question2" >
            <option>3</option>
            <option>23</option>
            <option>5</option>
            <option>6</option>
        </select><span id="Question2Status"></span><br />
    </div><br /> <br />   
    <h3>Subtraction</h3><br />
    <div id="Group2">
        2 - 1 = 
        <select id="Question3" >
            <option>2</option>
            <option>0</option>
            <option>1</option>
            <option>-2</option>
        </select><span id="Question3Status"></span><br />
        2 - 2 = 
        <select id="Question4" >
            <option>2</option>
            <option>-2</option>
            <option>0</option>
            <option>-4</option>
        </select><span id="Question4Status"></span><br />
    </div><br /><br />
    <input id="Submit1" type="button" value="Check Answers" onclick="done()" />
    <input id="Reset1" type="button" value="Start Again" onclick="resethandler()" />
</form>
</body>
</html>
<%@ Page Language="C#" %>

<!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 id="Head1" >
    <title>Custom Events Example</title>
</head>
<body>
<form id="form1" >
    <asp:ScriptManager ID="ScriptManager1"  >
        <Scripts>
           <asp:ScriptReference Path="question.js" />
           <asp:ScriptReference Path="section.js" />
       </Scripts>
    </asp:ScriptManager>
    <script type="text/javascript">
    // Add handler to init event
    Sys.Application.add_init(appInitHandler);

    function appInitHandler() {
      // create components
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question1'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question2'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question3'));
      $create(Demo.Question, {correct: '3'},
        {select: onAnswer},null, $get('Question4'));
      $create(Demo.Section, null,
        {complete: onSectionComplete},null, $get('group1'));
      $create(Demo.Section, null,
        {complete: onSectionComplete},null, $get('group2'));
    }

    function onAnswer(question) {
        // If all questions in this section answered, 
        // raise complete event
        var section = question.get_element().parentElement;
        var questions = section.children;
        $get(question.get_id() + 'Status').innerHTML = '';
        for (var i=0; i<questions.length; i++) {
            if (questions[i].selectedIndex === -1) {
                return;
            }
        }
        $find(section.id).raiseComplete();
    }

    function onSectionComplete(section) {
        // Change background color of <div>.
        section.get_element().style.backgroundColor = 'yellow';
    }

    function done() {
        // Display correct answers where needed.
        var c = Sys.Application.getComponents();
        for (var i=0; i<c.length; i++) {
            var type = Object.getType(c[i]).getName();
            if (type !== 'Demo.Question') continue;
            var element = c[i].get_element();
            var answer = element.selectedIndex;
            var correct = $find(c[i].get_id()).get_correct();
            var statusElement = c[i].get_id() + 'Status';
            if (answer !== correct) {
                $get(statusElement).innerHTML = 'Incorrect. Try again.';
            }
            else
            {
                $get(statusElement).innerHTML = 'Correct.';
            }
        }
    }

    function resethandler() {
        var c = Sys.Application.getComponents();
        for (var i=0; i<c.length; i++) {
            var type = Object.getType(c[i]).getName();
            if (type === 'Demo.Question') {
                var element = c[i].get_element();
                element.selectedIndex = -1;
                var answer = element.selectedIndex;
                var statusElement = c[i].get_id() + 'Status';
                $get(statusElement).innerHTML = '';
            }
            else if (type === 'Demo.Section') {
                c[i].get_element().style.backgroundColor = 'White';

            }
        }
    }
    </script>
    <h3>Addition</h3><br />
    <div id="Group1">
        2 + 2 = 
        <select id="Question1">
            <option>2</option>
            <option>22</option>
            <option>4</option>
            <option>5</option>
        </select><span id="Question1Status"></span><br />
        2 + 3 = 
        <select id="Question2" >
            <option>3</option>
            <option>23</option>
            <option>5</option>
            <option>6</option>
        </select><span id="Question2Status"></span><br />
    </div><br /> <br />   
    <h3>Subtraction</h3><br />
    <div id="Group2">
        2 - 1 = 
        <select id="Question3" >
            <option>2</option>
            <option>0</option>
            <option>1</option>
            <option>-2</option>
        </select><span id="Question3Status"></span><br />
        2 - 2 = 
        <select id="Question4" >
            <option>2</option>
            <option>-2</option>
            <option>0</option>
            <option>-4</option>
        </select><span id="Question4Status"></span><br />
    </div><br /><br />
    <input id="Submit1" type="button" value="Check Answers" onclick="done()" />
    <input id="Reset1" type="button" value="Start Again" onclick="resethandler()" />
</form>
</body>
</html>

El ejemplo siguiente muestra el archivo Question.js que define el control Demo.Question.

Type.registerNamespace("Demo");

// Constructor
Demo.Question = function(element) {

    Demo.Question.initializeBase(this, [element]);

    // Create a delegate for the select event.
    this._selectDelegate = null;
}
Demo.Question.prototype = {

    // correct property accessors
    get_correct: function() {
        return this.get_element().name - 1;
    },
    set_correct: function(value) {
        this.get_element().name = value;
    },

    // Bind and unbind to select event.
    add_select: function(handler) {
        this.get_events().addHandler('select', handler);
    },
    remove_select: function(handler) {
        this.get_events().removeHandler('select', handler);
    },

    // Release resources before control is disposed.
    dispose: function() {

        var element = this.get_element();

        if (this._selectDelegate) {
            $clearHandlers(element);
            delete this._selectDelegate;
        }

        Demo.Question.callBaseMethod(this, 'dispose');
    },

    initialize: function() {

        var element = this.get_element();

        // Make sure no option is selected.
        element.value = ""; 

        // Attach delegate to select event.
        if (this._selectDelegate === null) {
            this._selectDelegate = Function.createDelegate(this, this._selectHandler);
        }
        Sys.UI.DomEvent.addHandler(element, 'change', this._selectDelegate);

        Demo.Question.callBaseMethod(this, 'initialize');

    },

    _selectHandler: function(event) {
        var h = this.get_events().getHandler('select');
        if (h) h(this, Sys.EventArgs.Empty);
    }
}
Demo.Question.registerClass('Demo.Question', Sys.UI.Control);

// 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();
Type.registerNamespace("Demo");

// Constructor
Demo.Question = function(element) {

    Demo.Question.initializeBase(this, [element]);

    // Create a delegate for the select event.
    this._selectDelegate = null;
}
Demo.Question.prototype = {

    // correct property accessors
    get_correct: function() {
        return this.get_element().name - 1;
    },
    set_correct: function(value) {
        this.get_element().name = value;
    },

    // Bind and unbind to select event.
    add_select: function(handler) {
        this.get_events().addHandler('select', handler);
    },
    remove_select: function(handler) {
        this.get_events().removeHandler('select', handler);
    },

    // Release resources before control is disposed.
    dispose: function() {

        var element = this.get_element();

        if (this._selectDelegate) {
            $clearHandlers(element);
            delete this._selectDelegate;
        }

        Demo.Question.callBaseMethod(this, 'dispose');
    },

    initialize: function() {

        var element = this.get_element();

        // Make sure no option is selected.
        element.value = ""; 

        // Attach delegate to select event.
        if (this._selectDelegate === null) {
            this._selectDelegate = Function.createDelegate(this, this._selectHandler);
        }
        Sys.UI.DomEvent.addHandler(element, 'change', this._selectDelegate);

        Demo.Question.callBaseMethod(this, 'initialize');

    },

    _selectHandler: function(event) {
        var h = this.get_events().getHandler('select');
        if (h) h(this, Sys.EventArgs.Empty);
    }
}
Demo.Question.registerClass('Demo.Question', Sys.UI.Control);

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

El ejemplo siguiente muestra el archivo Section.js que define el control Demo.Section.

Type.registerNamespace("Demo");

// Constructor
Demo.Section = function(element) {

    Demo.Section.initializeBase(this, [element]);
}
Demo.Section.prototype = {

    // Create add and remove accessors fot the complete event.
    add_complete: function(handler) {
        this.get_events().addHandler("complete", handler);
    },
    remove_complete: function(handler) {
        this.get_events().removeHandler("complete", handler);
    },

    // Create a function to raise the complete event.
    raiseComplete: function() {
        var h = this.get_events().getHandler('complete');
        if (h) h(this);
    },

    // Release resources before control is disposed.
    dispose: function() {
        var element = this.get_element();
        $clearHandlers(element);
        Demo.Section.callBaseMethod(this, 'dispose');
    }
}
Demo.Section.registerClass('Demo.Section', Sys.UI.Control);

// 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();
Type.registerNamespace("Demo");

// Constructor
Demo.Section = function(element) {

    Demo.Section.initializeBase(this, [element]);
}
Demo.Section.prototype = {

    // Create add and remove accessors fot the complete event.
    add_complete: function(handler) {
        this.get_events().addHandler("complete", handler);
    },
    remove_complete: function(handler) {
        this.get_events().removeHandler("complete", handler);
    },

    // Create a function to raise the complete event.
    raiseComplete: function() {
        var h = this.get_events().getHandler('complete');
        if (h) h(this);
    },

    // Release resources before control is disposed.
    dispose: function() {
        var element = this.get_element();
        $clearHandlers(element);
        Demo.Section.callBaseMethod(this, 'dispose');
    }
}
Demo.Section.registerClass('Demo.Section', Sys.UI.Control);

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

Vea también

Tareas

Crear controles de cliente de AJAX personalizados

Referencia

Sys.Application (Clase)

Sys.WebForms.PageRequestManager (Clase)

Sys.UI.DomEvent (Clase)

Sys.EventHandlerList (Clase)