Обработка событий в среде .NET Framework

93

В 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("Цвет изменился!");
        }
    }
}
Реализация события

Как видите, данный пример наглядно демонстрирует создание пользовательского события нажатия клавиш, при этом обработчик события, реализованный с помощью лямбда-выражения содержит целый набор команд, для работы с консолью.

Пройди тесты
Лучший чат для C# программистов