(转)创建自定义客户端事件

(转自MSDN http://msdn.microsoft.com/en-us/bb398781(zh-cn).aspx

ASP.NET 中的 AJAX 功能包括一个完整的多层客户端事件模型。Sys.Application 类提供应用程序级别的事件。Sys.WebForms.PageRequestManager 类提供与涉及部分页呈现的页面部分相关的事件。各个组件(如控件和行为)具有各自的事件。有关这些事件的更多信息,请参见 AJAX 客户端生命周期事件

ASP.NET 也使您能够将事件添加到客户端生命周期。Sys.UI.DomEvent 类使您能够将 HTML 文档对象模型 (DOM) 事件绑定到自定义 ASP.NET AJAX 组件。此外,Sys.EventHandlerList 类可让您直接创建新的 ASP.NET AJAX 客户端事件。

在多数情况下,要使用的事件与在 HTML DOM 中定义的事件对应。例如,自定义 ASP.NET AJAX 按钮控件可能使用它附加到的 HTML <button> 元素的 click 事件。若要将基于 DOM 的事件绑定到 ASP.NET AJAX 应用程序或自定义组件,请使用 DomEvent 类的 addHandler 方法,如以下示例所示:

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

也可以使用 $addHandler 快捷方式,如以下示例所示:

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

addHandler 方法采用三个参数:elementeventNamehandlerelement 参数是对公开事件的 DOM 元素的引用。eventName 参数是 DOM 事件本身的名称。handler 参数是对在引发事件时要调用的函数的引用。有关更多信息,请参见 Sys.UI.DomEvent addHandler 方法

若要移除 DOM 事件的处理程序,请调用 Sys.UI.DomEvent.removeHandler 方法或 $removeHandler 快捷方式,并传递相应的参数,这些参数与您传递给 addHandler 的参数相同。

说明:

传递到 addHandlerremoveHandler 函数的事件名称不应包括“on”前缀。例如,应使用“click”而非“onclick”。

若要为自定义 ASP.NET AJAX 组件的事件添加新的事件处理程序,请使用 Sys.EventHandlerList 类的 addHandler 方法。ASP.NET AJAX 事件模型中的所有客户端事件和关联事件处理程序存储在一个 EventHandlerList 对象中,该对象是用于此目的的专用词典。每个组件(包括当前 Application 对象)都具有各自的 EventHandlerList 实例。通过向 EventHandlerList 对象添加相应的项,可向关联组件添加新的事件和事件处理程序。可使用以下语法添加事件:

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

Sys.Component 类的 events 属性返回该组件的 EventHandlerList 实例。events 属性由 Sys.UI.ControlSys.UI.BehaviorSys.Application 类继承。event 参数是要为其添加处理程序的新事件或现有事件的名称。handler 参数是对在引发事件时要调用的函数的引用。通过将 event 参数设置为新值,可向字典添加新事件。

若要从字典中移除自定义事件,请采用 Sys.EventHandlerList 类的 removeHandler 方法,该方法将使用与 addHandler 相同的参数。

若要向 Microsoft AJAX Library 中已定义的事件添加处理程序,请为该事件使用 add_ 访问器,如以下示例所示:

Sys.Application.add_load(myLoadHandler);

若要引发自定义事件,请调用 EventHandlerList 实例的 getHandler 方法,并传递该事件的名称作为参数。此方法返回一个函数,该函数聚合作为事件的处理程序的所有函数。调用返回的函数以引发事件,如以下示例所示:

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

按照约定,事件处理程序将采用两个参数:sendereventArgs。sender 是事件应用于的组件,通常为 thiseventArgs 参数引用 Sys.EventArgs 对象。此对象可以包含传递给事件的信息,如鼠标坐标。只要 getHandler 返回的函数的签名与所有关联处理程序函数的签名匹配,就可以省略 sendereventArgs 参数。但是,建议的做法是包括这两个参数,如前面显示的示例中所示。

说明

下面的示例创建一个简单的多选测试,此测试包含两个部分。回答完某个部分中的所有问题后,此部分的背景色会发生改变。若用户在测试结束时单击按钮,则每个问题旁边的状态消息会显示答案是否正确。

应用程序包括两个自定义控件的实例。Question 控件附加到 HTML <select> 元素,而 Section 控件附加到包含一个或多个 Question 控件的 <div> 元素。Question 控件公开 select 事件,该事件通过 Sys.UI.DomEvent 实例绑定到基础 <select> 元素的 onChange 事件。Section 控件公开 complete 事件,当回答完 Section 实例中的所有 Question 控件时,该事件由一个用户定义的函数引发。

代码

下面的示例演示可创建组件实例并处理事件的 Default.aspx 页。

Visual Basic
<%@ Page Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html >
<head id="Head1" runat="server">
    <title>Custom Events Example</title>
</head>
<body>
<form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" >
        <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 >
<head id="Head1" runat="server">
    <title>Custom Events Example</title>
</head>
<body>
<form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" >
        <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>

下面的示例演示对 Demo.Question 控件进行定义的 Question.js 文件。

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

下面的示例演示对 Demo.Section 控件进行定义的 Section.js 文件。

Visual Basic
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();
posted @ 2010-01-04 18:21  DreamsHunter  阅读(496)  评论(0编辑  收藏  举报