更新:2007 年 11 月
ASP.NET 中的 AJAX 功能包括一个完整的多层客户端事件模型。Sys.Application 类提供应用程序级别的事件。Sys.WebForms.PageRequestManager 类提供与涉及部分页呈现的页面部分相关的事件。各个组件(如控件和行为)具有各自的事件。有关这些事件的更多信息,请参见 AJAX 客户端生命周期事件。
ASP.NET 也使您能够将事件添加到客户端生命周期。Sys.UI.DomEvent 类使您能够将 HTML 文档对象模型 (DOM) 事件绑定到自定义 ASP.NET AJAX 组件。此外,Sys.EventHandlerList 类可让您直接创建新的 ASP.NET AJAX 客户端事件。
附加到 DOM 事件
在多数情况下,要使用的事件与在 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”。 |
添加和移除自定义事件处理程序
若要为自定义 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);
引发自定义事件
若要引发自定义事件,请调用 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 参数。但是,建议的做法是包括这两个参数,如前面显示的示例中所示。
示例
说明
下面的示例创建一个简单的多选测试,此测试包含两个部分。回答完某个部分中的所有问题后,此部分的背景色会发生改变。若用户在测试结束时单击按钮,则每个问题旁边的状态消息会显示答案是否正确。
应用程序包括两个自定义控件的实例。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 xmlns="http://www.w3.org/1999/xhtml">
<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 xmlns="http://www.w3.org/1999/xhtml">
<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();