Обработка событий в C#
Под событием понимают сигнал прерывания, возникающий синхронно или асинхронно по отношению к сценарию реализации приложения. Например, нажатие на клавиши переключения языка русский – латинский.
События связаны с объектами, в которых происходят изменения, связанные с данным событием. Когда происходит событие, вызываются все обработчики этого события, но обработка выполняется только для того объекта, для которого это событие имеет смысл. Обработка событий задается делегатами.
События имеют следующие свойства (применяемые в MSDN термины).
• Издатель определяет момент вызова события, подписчики определяют предпринятое ответное действие.
• У события может быть несколько подписчиков. Подписчик может обрабатывать несколько событий от нескольких издателей.
• События, не имеющие подписчиков, никогда не возникают.
• Обычно события используются для оповещения о действиях пользователя, таких как нажатия кнопок или выбор меню и их пунктов в графическом пользовательском интерфейсе.
• Если событие имеет несколько подписчиков, то при его возникновении происходит синхронный вызов обработчиков событий.
• В библиотеке классов .NET Framework в основе событий лежит делегат EventHandler и базовый класс EventArgs.
События являются членами класса и объявляются с помощью ключевого слова event. Чаще всего для этой цели используется следующая форма (Шилдт):
event делегат_события имя_события;
где делегат_события обозначает имя делегата, используемого для поддержки события, а имя_события - конкретный объект объявляемого события (экземпляр).
Рассмотрим для начала очень простой пример.
// Объявить тип делегата для события,
delegate void MyEventHandler();
// Объявить класс, содержащий событие,
class MyEvent
{
public event MyEventHandler SomeEvent; // Здесь ссылка
// Этот метод вызывается для запуска (обработки) события,
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent();
}
}
class EventDemo
{
// Обработчик события,
static void Handler()
{
Console.WriteLine("Произошло событие");
}
static void Main()
{
MyEvent evt = new MyEvent();
// Добавить метод Handler() в список событий,
evt.SomeEvent += Handler;
// Запустить событие,
evt.OnSomeEvent();
Console.ReadKey();
}
}
Вот какой результат получается при выполнении этого кода.
Произошло событие
Несмотря на всю свою простоту, данный пример кода содержит все основные элементы, необходимые для обработки событий. Он начинается с объявления типа делегата для обработчика событий, как показано ниже.
delegate void MyEventHandler();
Все события обрабатываются с помощью делегатов. Поэтому тип делегата события определяет возвращаемый тип и сигнатуру для события. В данном случае параметры события отсутствуют, но их разрешается указывать.
Далее создается класс события MyEvent. В этом классе объявляется событие SomeEvent в следующей строке кода.
public event MyEventHandler SomeEvent;
Обратите внимание на синтаксис этого объявления. Ключевое слово event уведомляет компилятор о том, что объявляется событие.
Кроме того, в классе MyEvent объявляется метод OnSomeEvent (), который вызывается, когда происходит событие. Это означает, что он В методе OnSomeEvent () вызывается обработчик события с помощью делегата SomeEvent.
if(SomeEvent != null) SomeEvent();
Как видите, обработчик вызывается лишь в том случае, если событие SomeEvent не является пустым. А поскольку интерес к событию должен быть зарегистрирован в других частях программы, чтобы получать уведомления о нем, то метод OnSomeEvent () может быть вызван до регистрации любого обработчика события. Но во избежание вызова по пустой ссылке делегат события должен быть проверен, чтобы убедиться в том, что он не является пустым.
В классе EventDemo создается обработчик событий Handler (). В данном простом примере обработчик событий просто выводит сообщение, но другие обработчики выполняют более содержательные функции. Далее в методе Main () создается объект класса события MyEvent, а Handler () регистрируется как обработчик этого события, добавляемый в список.
MyEvent evt = new MyEvent();
// Добавить метод Handler() в список событий,
evt.SomeEvent += Handler;
Обратите внимание на то, что обработчик добавляется в список с помощью оператора +=. События поддерживают только операторы += и -=. В данном случае метод Handler () является статическим, но в качестве обработчиков событий могут также служить методы экземпляра.
И наконец, запускается обработка событие, как показано ниже.
// Запустить событие,
evt.OnSomeEvent();
Вызов метода OnSomeEvent () приводит к вызову всех событий, зарегистрированных обработчиком. В данном случае зарегистрирован только один такой обработчик, но их может быть больше, как поясняется в следующем разделе.
В приведенной ниже программе создается обработчик событий, связанных с нажатием клавиш. Всякий раз, когда на клавиатуре нажимается клавиша, вызывается метод OnKeyPress () и запускается обработка события KeyPress. Следует заметить, что в этой программе формируются .NET- совместимые события и что их обработчики предоставляются в лямбда-выражениях (Шилдт).
// Пример обработки событий, связанных с нажатием клавиш на клавиатуре.
// Создать класс, производный от класса EventArgs и
// хранящий символ нажатой клавиши.
class KeyEventArgs: EventArgs
{
public char ch;
}
// Объявить класс события, связанного с нажатием клавиш на клавиатуре,
class KeyEvent
{
public event EventHandler<KeyEventArgs> KeyPress;
// Этот метод вызывается при нажатии клавиши,
public void OnKeyPress(char key)
{
KeyEventArgs k = new KeyEventArgs();
if (KeyPress != null)
{
k.ch = key;
KeyPress(this, k);
}
}
}
// Продемонстрировать обработку события типа KeyEvent.
class KeyEventDemo
{
static void Main()
{
KeyEvent kevt = new KeyEvent();
ConsoleKeyInfo key;
int count = 0;
// Использовать лямбда-выражение для факта нажатия клавиши.
kevt.KeyPress += (sender, e) =>// Лямбда-выражение
Console.WriteLine(" Получено сообщение о нажатии клавиши: " + e.ch);
// Использовать лямбда-выражение для подсчета нажатых клавиш.
kevt.KeyPress += (sender, e) => count++; // count - это внешняя переменная
Console.WriteLine("Введите несколько символов. " +
"По завершении введите точку.");
do
{
key = Console.ReadKey();
kevt.OnKeyPress(key.KeyChar);
} while (key.KeyChar != .);
Console.WriteLine("Было нажато " + count + " клавиш.");
}
}
В среде .NET Framework предоставляется встроенный обобщенный делегат под названием EventHandler <TEventArgs>. Этот делегат связывает событие с его обработчиком. Для вызова события требуются два элемента:
• делегат, который ссылается на метод, вызываемый в ответ на событие;
• Дополнительно класс, который содержит данные события, если событие содержит данные. (msdn)
Объявление делегата имеет форму:
[SerializableAttribute]
public delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e)
Параметры типа
TEventArgs - Тип данных, создаваемых событием.
Параметры
sender - Тип: System.Object - источник события.
e - Тип: EventArgs - объект, содержащий данные о событии.
Метод, определяемый делегатом, имеет тип возврата void. Первый параметр типа Object связан с объектом, порождающим событие. Второй параметр, производный от типа EventArgs, содержит информацию о событии и передает все поля, необходимые для обработки события (нажатую клавишу, информацию о кнопке мыши (правая, левая) и т. д.).
При работе с графическим интерфейсом (WindowsFormsApplication) обработчики событий выбираются из списка событий, связанных с элементом управления. Ниже приведен пример проверки щелчка правой кнопкой по обычной кнопке.
private void button1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
textBox1.Text = "Вы щелкнули правой кнопкой";
}
}
Обработка событий в C#
Лекции по предмету «Программирование»