Создание пользовательских клиентских событий
Обновлен: Ноябрь 2007
Функциональные возможности AJAX в ASP.NET предоставляют полную многоуровневую модель клиентских событий. Класс Sys.Application предоставляет события на уровне приложения. Класс Sys.WebForms.PageRequestManager предоставляет события, которые относятся к частям страницы, включенным в частичную отрисовку страницы. Отдельные компоненты, такие как элементы управления и расширения функциональности, имеют собственные события. Дополнительные сведения об этих событиях см. в разделе События жизненного цикла клиента AJAX.
ASP.NET также позволяет добавлять события в жизненный цикл клиента. Класс Sys.UI.DomEvent позволяет выполнять привязку событий объектной модели HTML-документов (DOM) к настраиваемым AJAX-компонентам ASP.NET. Кроме этого, класс Sys.EventHandlerList позволяет создавать новые события AJAX-клиента ASP.NET автоматически.
Присоединение к событиям DOM
Во многих случаях событие, с которым необходимо выполнить работу, соответствует событию, определенному в модели HTML DOM. Например, в пользовательском элементе управления ASP.NET AJAX "Кнопка" может быть использовано событие click HTML-элемента <button>, к которому присоединен данный элемент управления. Чтобы выполнить привязку события на основе DOM к AJAX-приложению ASP.NET или пользовательскому компоненту, следует использовать метод addHandler класса DomEvent, как показано в следующем примере.
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". Например, вместо "onclick" используйте "click". |
Добавление и удаление пользовательских обработчиков событий
Чтобы добавить новый обработчик событий для события пользовательского AJAX-компонента ASP.NET, используйте метод addHandler класса Sys.EventHandlerList. Все клиентские события и связанные с этими событиями обработчики в модели событий ASP.NET AJAX сохраняются в объекте EventHandlerList, который является специализированным словарем для этой цели. Каждый компонент, включая текущий объект Application, имеет собственный экземпляр EventHandlerList. При добавлении элемента в объект EventHandlerList, в связанный компонент добавляется новое событие и обработчик событий. Добавьте события с помощью следующего синтаксиса:
this.get_events().addHandler(event, handler);
Свойство events класса Sys.Component возвращает экземпляр EventHandlerList для этого компонента. Свойство events наследуется от классов Sys.UI.Control, Sys.UI.Behavior и Sys.Application. Параметр event является именем нового или существующего события, для которого добавляется обработчик. Параметр handler является ссылкой на функцию, которую необходимо вызвать при возникновении события. Новый элемент добавляется в словарь с помощью задания параметру event нового значения.
Чтобы удалить пользовательское событие из словаря, используйте метод removeHandler класса Sys.EventHandlerList, который принимает те же самые параметры, что и метод addHandler.
Чтобы добавить обработчики к событиям, которые уже определены в Microsoft AJAX (библиотека), используйте метод доступа add_ для данного события, как показано в следующем примере.
Sys.Application.add_load(myLoadHandler);
Вызов пользовательских событий
Чтобы вызвать пользовательское событие, вызовите метод getHandler экземпляра EventHandlerList, передав в этот метод в качестве параметра имя события. Этот метод возвращает функцию, собирающую все функции, которые являются обработчиками для данного события. Вызовите возвращенную функцию, чтобы вызвать событие, так как показано в следующем примере.
var h = this.get_events().getHandler('myCustomEvent')
if (h) h(this, Sys.EventArgs.Empty);
По соглашению обработчики событий принимают два параметра: sender и eventArgs. Отправитель является компонентом, к которому применяется событие, как правило this. Параметр eventArgs ссылается на объект Sys.EventArgs. Этот объект может содержать сведения, передаваемые событию, например координаты события. Можно опустить параметры sender и eventArgs, поскольку подпись функции, возвращенной методом getHandler, соответствует подписи функций для всех связанных обработчиков. Однако рекомендуется включать параметры, как показано в примере, приведенном ранее.
Пример
Описание
В данном примере создается простой тест с двумя разделами и с несколькими вариантами выбора. При ответе на все вопросы раздела фоновый цвет раздела изменяется. Когда пользователь нажимает кнопку в конце теста, сообщение о состоянии возле каждого вопроса показывает, правильный ли ответ был дан.
В приложение входят экземпляры двух пользовательских элементов управления. Элемент управления Question присоединяется к HTML-элементу <select>, а элемент управления Section присоединяется к элементу <div>, который содержит один или несколько элементов управления Question. Элемент управления Question предоставляет событие select, которое привязано к событию onChange базового элемента <select> с помощью экземпляра Sys.UI.DomEvent. Элемент управления Section предоставляет событие complete, которое вызывается пользовательской функцией, когда для всех элементов управления Question в экземпляре Section получен ответ.
Код
В следующем примере показана страница "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>
В следующем примере показан файл "Question.js", который определяет элемент управления 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();
В следующем примере показан файл "Section.js", который определяет элемент управления 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();
См. также
Задачи
Создание пользовательских клиентских элементов управления AJAX