(转)创建自定义客户端事件
(转自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 客户端事件。
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
在多数情况下,要使用的事件与在 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 方法采用三个参数:element、eventName 和 handler。element 参数是对公开事件的 DOM 元素的引用。eventName 参数是 DOM 事件本身的名称。handler 参数是对在引发事件时要调用的函数的引用。有关更多信息,请参见 Sys.UI.DomEvent addHandler 方法。
若要移除 DOM 事件的处理程序,请调用 Sys.UI.DomEvent.removeHandler 方法或 $removeHandler 快捷方式,并传递相应的参数,这些参数与您传递给 addHandler 的参数相同。
![]() |
---|
传递到 addHandler 和 removeHandler 函数的事件名称不应包括“on”前缀。例如,应使用“click”而非“onclick”。 |
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
若要为自定义 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.Control、Sys.UI.Behavior 和 Sys.Application 类继承。event 参数是要为其添加处理程序的新事件或现有事件的名称。handler 参数是对在引发事件时要调用的函数的引用。通过将 event 参数设置为新值,可向字典添加新事件。
若要从字典中移除自定义事件,请采用 Sys.EventHandlerList 类的 removeHandler 方法,该方法将使用与 addHandler 相同的参数。
若要向 Microsoft AJAX Library 中已定义的事件添加处理程序,请为该事件使用 add_ 访问器,如以下示例所示:
Sys.Application.add_load(myLoadHandler);
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
若要引发自定义事件,请调用 EventHandlerList 实例的 getHandler 方法,并传递该事件的名称作为参数。此方法返回一个函数,该函数聚合作为事件的处理程序的所有函数。调用返回的函数以引发事件,如以下示例所示:
var h = this.get_events().getHandler('myCustomEvent') if (h) h(this, Sys.EventArgs.Empty);
按照约定,事件处理程序将采用两个参数:sender 和 eventArgs。sender 是事件应用于的组件,通常为 this。eventArgs 参数引用 Sys.EventArgs 对象。此对象可以包含传递给事件的信息,如鼠标坐标。只要 getHandler 返回的函数的签名与所有关联处理程序函数的签名匹配,就可以省略 sender 和 eventArgs 参数。但是,建议的做法是包括这两个参数,如前面显示的示例中所示。
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
说明
下面的示例创建一个简单的多选测试,此测试包含两个部分。回答完某个部分中的所有问题后,此部分的背景色会发生改变。若用户在测试结束时单击按钮,则每个问题旁边的状态消息会显示答案是否正确。
应用程序包括两个自定义控件的实例。Question 控件附加到 HTML <select> 元素,而 Section 控件附加到包含一个或多个 Question 控件的 <div> 元素。Question 控件公开 select 事件,该事件通过 Sys.UI.DomEvent 实例绑定到基础 <select> 元素的 onChange 事件。Section 控件公开 complete 事件,当回答完 Section 实例中的所有 Question 控件时,该事件由一个用户定义的函数引发。
代码
下面的示例演示可创建组件实例并处理事件的 Default.aspx 页。
<%@ 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 文件。
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 文件。
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();