Обработка событий в среде .NET Framework
В C# разрешается формировать какие угодно разновидности событий. Но ради совместимости программных компонентов со средой .NET Framework следует придерживаться рекомендаций, установленных для этой цели корпорацией Microsoft. Эти рекомендации, по существу, сводятся к следующему требованию: у обработчиков событий должны быть два параметра. Первый из них — ссылка на объект, формирующий событие, второй — параметр типа EventArgs, содержащий любую дополнительную информацию о событии, которая требуется обработчику. Таким образом, .NET-совместимые обработчики событий должны иметь следующую общую форму:
void обработчик(object отправитель, EventArgs е) { //... }
Как правило, отправитель — это параметр, передаваемый вызывающим кодом с помощью ключевого слова this. А параметр е типа EventArgs содержит дополнительную информацию о событии и может быть проигнорирован, если он не нужен.
Сам класс EventArgs не содержит поля, которые могут быть использованы для передачи дополнительных данных обработчику. Напротив, EventArgs служит в качестве базового класса, от которого получается производный класс, содержащий все необходимые поля. Тем не менее в классе EventArgs имеется одно поле Empty типа static, которое представляет собой объект типа EventArgs без данных.
В среде .NET Framework предоставляется встроенный обобщенный делегат под названием EventHandler<TEventArgs>. В данном случае тип TEventArgs обозначает тип аргумента, передаваемого параметру EventArgs события.
Для обработки многих событий параметр типа EventArgs оказывается ненужным. Поэтому с целью упростить создание кода в подобных ситуациях в среду .NET Framework внедрен необобщенный делегат типа EventHandler. Он может быть использован для объявления обработчиков событий, которым не требуется дополнительная информация о событиях.
Ниже приведен пример программы, в которой формируется .NET-совместимое событие:
// Реализуем программу реагирующую на события // нажатия клавиш - вызывающих специализированные команды консоли using System; namespace ConsoleApplication1 { // Производный класс от EventArgs class MyEventArgs : EventArgs { public char ch; } class KeyEvent { // Создадим событие, используя обобщенный делегат public event EventHandler<MyEventArgs> KeyDown; public void OnKeyDown(char ch) { MyEventArgs c = new MyEventArgs(); if (KeyDown != null) { c.ch = ch; KeyDown(this, c); } } } class Program { static void Main() { KeyEvent evnt = new KeyEvent(); evnt.KeyDown += (sender, e) => { switch (e.ch) { case 'C': { MyColor(true); break; } case 'B': { MyColor(false); break; } case 'S': { Console.Write("\nВведите длину: "); try { int Width = int.Parse(Console.ReadLine()) / 8; Console.Write("Введите ширину: "); int Height = int.Parse(Console.ReadLine()) / 8; Console.WindowWidth = Width; Console.WindowHeight = Height; Console.WriteLine(); } catch (FormatException) { Console.WriteLine("Неверный формат!"); } catch (ArgumentOutOfRangeException) { Console.WriteLine("Окно настолько не растянется!"); } break; } case 'T': { Console.Write("\nВведите новый заголовок: "); string s = Console.ReadLine(); Console.Title = s; Console.WriteLine(); break; } case 'R': { Console.ForegroundColor = ConsoleColor.White; Console.BackgroundColor = ConsoleColor.Black; Console.WriteLine(); break; } case 'E': { Console.Beep(); break; } default: { Console.WriteLine("\nТакая команда не найдена!"); break; } } }; ConsoleTitle(); char ch; do { Console.Write("Введите комманду: "); ConsoleKeyInfo key; key = Console.ReadKey(); ch = key.KeyChar; evnt.OnKeyDown(key.KeyChar); } while (ch != 'E'); } // Несколько вспомогательных методов static void ConsoleTitle() { CC(ConsoleColor.Green); Console.WriteLine("***************************\n\nПрограмма настройки консоли" + "\n___________________________\n"); CC(ConsoleColor.Yellow); Console.WriteLine("Управляющие команды: \n"); Command("C", "Поменять цвет текста"); Command("B", "Поменять цвет фона"); Command("S", "Поменять размер окна"); Command("T", "Поменять заголовок"); Command("R", "Сбросить изменения"); Command("E", "Выход"); Console.WriteLine(); } static void CC(ConsoleColor color) { Console.ForegroundColor = color; } static void Command(string s1, string s2) { CC(ConsoleColor.Red); Console.Write(s1); CC(ConsoleColor.White); Console.Write(" - " + s2+"\n"); } static void MyColor(bool F_or_B) { link1: Console.Write("\nВведите цвет: "); string s = Console.ReadLine(); switch (s) { case "Black": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Black; else Console.BackgroundColor = ConsoleColor.Black; break; } case "Yellow": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Yellow; else Console.BackgroundColor = ConsoleColor.Yellow; break; } case "Green": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Green; else Console.BackgroundColor = ConsoleColor.Green; break; } case "Red": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Red; else Console.BackgroundColor = ConsoleColor.Red; break; } case "Blue": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Blue; else Console.BackgroundColor = ConsoleColor.Blue; break; } case "Gray": { if (F_or_B) Console.ForegroundColor = ConsoleColor.Gray; else Console.BackgroundColor = ConsoleColor.Gray; break; } case "White": { if (F_or_B) Console.ForegroundColor = ConsoleColor.White; else Console.BackgroundColor = ConsoleColor.White; break; } default: { Console.WriteLine("Такой цвет я не знаю :("); goto link1; } } Console.WriteLine("Цвет изменился!"); } } }
Как видите, данный пример наглядно демонстрирует создание пользовательского события нажатия клавиш, при этом обработчик события, реализованный с помощью лямбда-выражения содержит целый набор команд, для работы с консолью.
Комментарии