Назад Уперед Зміст

Події і делегати

Подієва модель роботи додатків

Один з найбільш сучасних підходів до побудови додатків - підхід, заснований на генерації і подальшій обробці подій.

Що таке подія

Подія - це перехід об'єкта з одного стану в інший. Наприклад, натискання клавіші, пересування курсора миші, зміна властивостей якогось об'єкта

Найпростіше подія - це подія, що повідомляє про початок або про завершення деякої процедури.

Генератор події

Події генеруються у відповідь на дії користувача. Це може бути клацання користувачем по кнопці, введення даних в текстове поле, і т.д.

Подія може бути згенеровано і без взаємодії з користувачем, наприклад, при виконанні деякого методу.

Обробник події

Реакція програми на подію проявляється у виконанні деяких дій. Для цього існують обробники подій - методи, які безпосередньо виконує дії.

Підписка на подія

При виникненні одного і того ж події, для об'єктів різних класів можуть виконуватися різні дії (викликатися різні обробники).

Наприклад, подія «Дзвінок». Реакція на цю подію:

Як же програма дізнається, що подія відбулася, і які обробники цієї події в різних класах потрібно викликати?

Тому є щось, що з'єднує події і обробники. Це підписка на події. При підписці на події вказується, в якому класі, які обробники повинні виконуватися у відповідь на виникнення події.

Для нашого прикладу, є дві підписки на подію «Дзвінок»:

Від події можна і відписатися. При цьому подія відбувається, але відповідний обробник не виконується.

Делегати

Що таке делегат

Делегат це клас. Об'єкти цього класу це прототипи функцій, тобто функцій з певною сигнатурою.

Сигнатура функції - це поєднання назви типу, який функція повертає, плюс назва типів входять параметрів (в порядку проходження).

Опис делегата

При описі змінної типу делегат вказується ключове слово delegate, а також функція, сигнатура якої збігається з типом делегата. Після цього делегат можна використовувати для виклику зазначеної функції.

Даний делегат Del може представляти будь-яку функцію типу void без значення, що повертається і з одним параметром типу string:
public delegate void Del(string message);

Даний делегат MyDel може представляти будь-яку функцію типу void без значення, що повертається і без параметрів:
public delegate void MyDel ();

Даний делегат Ddel може представляти будь-яку функцію типу void без значення, що повертається і з двома параметрами: перший типу int, другий типу double.

Що таке об'єкт класу делегат

Фундаментальна відмінність змінної-типу делегат від раніше розглянутих полягає в тому, що в якості значення змінної-цього типу можна привласнити метод відповідний певної сигнатуре.

В будь-який метод можна зрадити в якості параметра об'єкт класу делегат, тобто можна в якості параметра передати в метод функцію.

Для створення об'єкта класу делегатів використовують конструктор:

public delegate void Ddel (int i, double j);

Метод, який передається як параметр делегата, повинен мати таку ж сигнатуру, як і оголошення делегата.

Приклад

Нехай в класі MathClass описані два методи з однаковою сигнатурою:

В класі Program:

Об'єкти класу Del це методи. Об'єкт d1 це фактично метод MultiplyNumbers, застосований до об'єкта m, а об'єкт d2, це метод AddNumbers застосований до того ж об'єкту.

А тепер додамо два методи з іншого сигнатурою. І оголосимо другий делегат.

Навіщо все це потрібно? Делегати є основою подій.

Події

Подія являє собою повідомлення, що посилається об'єктом, щоб сигналізувати про звершення якої-небудь дії. Ця дія може бути викликано в результаті взаємодії з користувачем, наприклад при натисканні кнопки миші, або може бути обумовлено логікою роботи програми.

Об'єкт, що викликає подія, називається відправником або видавцем події. Об'єкт, який стежить за подією і реагує на нього, називається одержувачем або передплатником події.

Події мають такі властивості:

При обміні подіями класу відправника подій ніхто не знає об'єкт або метод, який буде отримувати (обробляти) сформовані відправником події. Необхідно, щоб між джерелом і одержувачем події був посередник. Саме для цього використовуються делегати.

Опис події

В основі механізму обробки подій лежать делегати, тому перш, ніж оголосити подія, необхідно оголосити делегат. Оголошення події схоже на оголошення змінної типу делегата, але з додаванням на початку ключового слова event. Для оголошення події використовується наступний синтаксис:

делегат змінна = new делегат (об'ект.метод);
event делегат подія;

Генерація події

Щоб згенерувати подія, вказується ім'я події, а потім в круглих дужках через кому перераховуються параметри події.

Перш ніж порушувати подія, рекомендується перевірити, чи не дорівнює чи null змінна, що описує подію.

Підписка і скасування підписки на події

Для підписки на подію для будь-якого об'єкта використовується оператор + =, після якого за допомогою ключового слова new викликається конструктор делегата, в якості параметра якого вказується ім'я методу, що представляє із себе обробник події.

Тут:

об'ект1 - об'єкт, який ініціює подія;

об'ект2 - об'єкт, який підписується на подію.

метод - обробник події для об'ект2.

Щоб скасувати передплату на події використовується та ж конструкція, тільки з оператором - =

Приклад

Нехай визначено три класи.

Перший клас буде вважати до 10, і виводити значення лічильника на консоль, використовуючи цикл.

Два інших класу чекатимуть, коли в першому класі лічильник дорахував, наприклад, до 7.

Після цього перший виведе на консоль фразу «Пора діяти, адже вже 7!»,

Другий виведе фразу «Точно, вже 7!»

Простіше кажучи, при виявленні значення 7, викликаються по одному методу, відповідно для кожного класу.

Порядок написання коду програми:

1. Моделювання ситуації

Підготуємо ці три простих класу:

Клас ClassCounter і його метод Count () в якому буде виконуватися рахунок.

Два інших класу (з іменами Handler_I і Handler_II), які повинні реагувати на виникнення події методами public void Message ().

2. Оформлення події.

Абстрагуємося від програмування. Подія, яке ми хочемо створити, буде представляти фразу "... лічильник рахує. І як тільки він буде дорівнює 7, повинні виконатися дії". Значить, нам необхідна умова «як тільки він буде дорівнює 7». Уявімо його за допомогою умовного оператора if.

В класі, в якому виникає подія, конструюємо його.

Спочатку визначаємо за методами, які повинні спрацювати при i = 7 їх сигнатуру (або прототип).

Сигнатура методу - це так звана специфікація (або простими словами «шаблон») будь-якого методу або методів. Є поєднанням назви типу, який метод повертає, плюс назва типів входять параметрів в порядку проходження.

Події засновані на делегатів. А делегат, кажучи дуже простою мовою - «змінна, що зберігає посилання на метод».

Наше подія буде посилатися на два методу. Ми повинні визначити сигнатури цих методів, і скласти на основі цих сигнатур делегати.

Якщо сигнатури у оброблювачів різні, то потрібно два делегата, якщо однакові, то один делегат. У наших оброблювачів сигнатури однакові: немає вихідного значення і немає параметрів. Тому делегат буде один.

Визначаємо делегат (назвемо його MethodContainer).

Далі, ми описуємо подія за допомогою ключового слова event і пов'язуємо його з цим делегатом (MethodContainer), а, отже, c методами, що мають таку ж сигнатуру, як у делегата.

Подія має бути public, тому що його повинні використовувати різні класи, яким потрібно якось відреагувати (класи Handler_I і Handler_II).

Далі запустимо наше подія onCount, в умови коли i = 7

Подія створено. Методи, які викличе ця подія, визначені по сигнатурам і на основі їх створено делегат. Подія, в свою чергу, створено на основі делегата. Пора показати події onCount, які ж все-таки методи повинні спрацювати (ми ж вказали тільки їх сигнатуру).

3. Підписка.

Повернемося в точку входу програми main і створимо об'єкти трьох наших класів.

Тепер зазначимо події onCount, методи, які повинні запуститися.

Відбувається це в такий спосіб:

об'ект1.собитіе + = new делегат (об'ект2.метод);
КлассІліОб'ект.ІмяСобития + = Класс або Об'ект Чий Метод повинен Запуститися. Метод, що Підходить По Сігнатуре

Ніяких скобочек після методу! Ми ж не викликаємо його, а просто вказуємо його назву.

Клас або об'єкт: вказуємо клас, якщо подія статичну, і об'єкт, якщо об'єкт був створений. У нашому прикладі всі три об'єкти створені, тому вказуємо об'єкт.

Тепер залишилося запустити метод Count класу ClassCounter і почекати, поки i стане рівним 7.

Як тільки i = 7, виникне подія onCount по делегатуMethodContainer, який (в свою чергу) запустить методи Message (), які були підписані на подію.

Результат:

Внесемо деякі зміни.

Результат:

Ще раз порядок написання коду програми:

  1. Моделювання ситуації:
  2. Оформлення події:
  3. Підписка на подію:

Назад Уперед Зміст