Представление события с точки зрения получателя

Получателем (адресатом) события может выступать любое приложение, объект или компонент, который нуждается в уведомлении, когда что-то происходит. Если имеется получатель события, то естественно, должен существовать и его отправитель. Работа отправителя заключается в генерации события. Отправителем может быть либо другой объект, либо сборка вашего приложения, или же — в случае системного событий, таких как щелчок мыши или нажатие клавиши — отправителем будет исполняющая система .NET. Важно отметить, что отправитель события ничего не знает том, кто его получает. Это делает события чрезвычайно полезными.

Теперь где-то внутри получателя будет метод, который отвечает за обработку события. Этот обработчик событий будет запускаться всякий раз, когда возникает зарегистрированное для него событие. И здесь вступают в действие делегаты. Поскольку отправитель не имеет никакого представления о получателе (получателях), между ними не может быть никаких ссылок. В качестве посредника используются делегаты. Отправитель определяет делегат, который будет использован получателем. Получатель, регистрирует обработчик события. Процесс прикрепления обработчика к событию называется привязкой события. Простой пример привязки события Click поможет нам проиллюстрировать этот процесс.

Во-первых, создадим простое приложение Windows Forms. Перетащим кнопку с панели инструментов и поместим ее на форму. В окне свойств переименуем кнопку в btnOne. В редакторе кода добавим следующую строку в текст конструктора Forml:

btnOne.Click += new EventHandler(Button_Click);

 

Теперь все, что нужно сделать в Visual Studio после ввода операции += — это нажать клавишу <ТаЬ> несколько раз, и редактор выполнит для нас всю остальную работу. В большинстве случаев это подходит. Однако в нашем примере имя обработчика событий по умолчанию не используется, поэтому мы должны самостоятельно ввести текст.

При этом происходит вот что: мы сообщаем исполняющей системе, что когда возникает событие Click для кнопки btnOne, то должен быть выполнен метод Button_Click. EventHandler — это делегат, который использует событие для назначения обработчика (Button_Click) событию (Click). Отметим, что мы использовали операцию += для добавления метода к списку делегатов. Все это значит, что событию можно назначить более одного обработчика. Поскольку это групповой делегат, к нему применимы все правила о добавлении множественных методов; однако нет никакой гарантии того, в каком порядке они будут вызваны. Продолжим дальше, перетащив в форму еще одну кнопку, и переименуем ее в btnTwo. Теперь свяжем событие Click кнопки btnTwo с тем же методом Button_Click, как показано ниже:

btnOne.Click += new EventHandler(Button_Click);

btnTwo. Click += new EventHandler (Button_Click);

 

Делегат EventHandler определен средой .NET Framework. Он находится в пространстве имен System, и все события, определенные в .NET Framework, используют его. Как уже упоминалось выше, список делегатов должен иметь одну и ту же сигнатуру. Очевидно, что это так же справедливо и для делегатов событий. Ниже показано определение метода Button_Click:

private void btnOne_Click(object sender, EventArgs e)

{

 

}

Относительно этого метода следует отметить несколько важных моментов. Во-первых, он всегда возвращает void. Обработчики событий не могут возвращать значений. Далее скажем о параметрах. Пока используется делегат EventHandler, параметрами будут object и EventArgs. Первый параметр — это объект, который возбудил событие. В данном примере это будет либо btnOne, либо btnTwo — в зависимости от того, какая кнопка была щелкнута. Благодаря тому, что передается ссылка на объект, вызвавший событие, можно привязывать один и тот же обработчик к более чем одному объекту. Например, вы можете определить один обработчик щелчков для нескольких кнопок и определять, какая именно кнопка нажата, опрашивая первый параметр.

Второй параметр — EventArgs — это объект, содержащий другую потенциально полезную информацию о событии. Этот параметр может быть любого типа, унаследованного от EventArgs.

Так, событие MouseDown использует MouseDownEventArgs. Он содержит такие свойства, как кнопка мыши, которая была нажата, координаты X и Y указателя, а также другую информацию, связанную с событием. Обратите внимание на шаблон имени, заканчивающийся на EventArgs. Позднее мы увидим, как создавать и применять пользовательский объект на базе EventArgs.

Также стоит обратить внимание на имя метода. По установленному соглашению любой обработчик событий должен придерживаться стиля «именования объект_событие».

Здесь объект — это объект, возбуждающий событие, а событие — само событие. Это всего лишь соглашение, но для хорошей читабельности кода его следует придерживаться.

Последнее, что нужно сделать в этом примере — добавить некоторый код, который на самом деле сделает что-то полезное в обработчике. Вспомним, что у нас две нопки используют один и тот же обработчик. То есть первое, что нужно сделать — определить, какая из них сгенерировала событие, а затем выполнить соответствующее действие. В данном примере мы просто выведем некоторый текст на метку формы. Для этого перетащим из панели инструментов на форму элемент управления типа метки и назовем ее lblInfо. Затем напишем следующий код в методе Button_Click:

 

if (((Button)sender).Name == "btnOne")

lblInfo.Text = "Нажата первая кнопка";

else

lblInfo.Text = "Нажата вторая кнопка";

 

Отметим, что поскольку параметр sender отправлен как объект, его нужно присти к типу объекта, вызвавшего событие, в данном случае — к Button. В этом примере мы используем свойство Name для определения кнопки, вызвавшей событие. Однако вы можете использовать другие свойства. Удобно использовать в этом сценарии свойство Tag, поскольку оно может хранить все, что вы пожелаете в него поместить. Чтобы увидеть, как работают групповые возможности делегата, добавим еще один метод к событию Click кнопки bthTwo. Используем имя метода по умолчанию. Тело конструктора формы теперь будет выглядеть примерно так:

this.btnOne.Click += new System.EventHandler(this.btnOne_Click);

this.btnTwo.Click += new System.EventHandler(this.btnOne_Click);

this.btnTwo.Click += new System.EventHandler(this.btnTwo_Click);

 

Если мы позволим Visual Studio самостоятельно создать заготовку, то увидим следующий метод-в конце исходного файла. Однако вызов функции MessageBox потребуется добавить вручную:


private void btnTwo_Click(object sender, EventArgs e)

{

MessageBox.Show("Это произошло только при событии щелчка на кнопке 2");

}

Если вернуться назад и использовать анонимные методы, то методы Button_Click и btnTwo_Click не понадобятся.

При запуске этого примера щелчок на кнопке btnOne изменит текст метки. Щелок на кнопке btnTwo не только изменит текст метки, но также отобразит MessageBox (окно сообщения). Напомним еще раз, что нет никаких гарантий того, что изменения текста метки произойдет до появления MessageBox, поэтому не пишите зависимый код в обработчиках.

Может показаться, что для того, чтобы во всем этом разобраться, необходимо изучить множество концепций, но на практике объем кодирования, которое нужно выполнить в приемнике, весьма невелик. Также следует иметь в виду, что писать приемники событий вам придется гораздо чаще, чем их отправители. По крайней мере, что касается пользовательского интерфейса Windows, Microsoft уже разработала все необходимые отправители событий, которые вам понадобятся (они закодированы в базовых классах .NET, в пространстве имен Windows.Forms).