|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Обробка подій
і делегати
Попередні версії
Visual Basic переконливо показали, що модель програмування, керована подіями
і заснована на застосуванні об'єктів, підвищує продуктивність праці програміста.
Варто було вам перетягнути елемент на форму, як він починав реагувати
на певні події. Наприклад, код процедури події Button1_click автоматично
виконувався при натисненні кнопки з ім'ям Button1.
Але, не дивлячись на ефективність, модель, використана в колишніх версіях
VB, була недостатньо гнучкою. Зокрема, в ній було важко визначати нові події,
а написати обробник, який обробляє відразу декілька подій, було
практично неможливо. У VB .NET зручність і ефективність об'єдналися з багатством
можливостей. Зазвичай використовується синтаксис, дуже близький до синтаксису колишніх версій VB,
при цьому VB .NET бере на себе всю «чорну роботу». Якщо
знадобиться зробити щось нестандартне — VB .NET надасть і таку можливість.
Розділ починається з опису моделі обробки подій, схожої на аналогічну модель
з попередніх версій VB (хоча і набагато могутнішою). Далі ми представимо нову для VB
концепцію делегатів і покажемо, як з їх допомогою повною мірою використовувати можливості
платформи .NET по обробці подій, а також вирішувати більш загальні завдання (наприклад,
організувати зворотний виклик функцій).
Оскільки суть об'єктно-орієнтованого програмування кінець кінцем зводиться
до обміну повідомленнями між взаємодіючими об'єктами, події повинні займати
певне місце в цій схемі. У якомусь відношенні вони нормально вписуються
в неї: об'єкт-джерело відправляє повідомлення, яке указує на виникнення
події. Але при
цьому виникає очевидна проблема: яким об'єктам слід відправляти повідомлення?
Оповіщати про кожну подію всі об'єкти, що зараз існують в програмі? Це
було б дуже неефективно. Для більший
ства об'єктів подія не представляє анінайменшого інтересу, а швидкодія стане
неприйнятна низьким. Замість цього
VB .NET намагається обмежити число одержувачів події, для чого використовується
модель «підписка/публікація». У цій моделі об'єкти-приймачі подій
реєструють об'єкти-джерела тих подій, які представляють для них інтерес.
На події від одного джерела можуть підписатися відразу декілька об'єктів-приймачів.
Про те, що джерело ініціювало подію, оповіщаються тільки зареєстровані
одержувачі.
Втім, реалізувати подібну схему не так просто. Які повідомлення повинні
передаватися приймачу від джерела? Як організувати їх відправку? Що повинне
відбуватися при отриманні повідомлення? Як мовилося вище, взаємодія між
об'єктами на базі обміну повідомленнями будується на виклику методів класу-приймача. Кінець
кінцем обробка подій будується за тим же принципом, але при цьому доводиться
враховувати ряд додаткових тонкощів. Загальний сенс що відбувається полягає
в тому, що при виникненні події об'єкт-джерело викликає заздалегідь
визначені функції об'єктів-приймачів. Функція приймача, що викликається,
реєструється джерелом події одночасно з реєстрацією об'єкту-приймача. Така
схема називається сповіщенням за допомогою зворотного виклику (callback
notification), тому що джерело події викликає метод приймача за заздалегідь
відомою йому адресою. На мал. 6.1 показаний об'ект-«начальник» з
подією Highrating, при виникненні викликаються різні методи об'єктів-приймачів.
У другій половині цього розділу буде розказано, як це відбувається в VB .NET.
Мал.
6.1. Схема сповіщення
за допомогою зворотного виклику
Передача
даних
функціям, що викликаються в результаті подій
Звичайно, ви
можете визначити власну сигнатуру для методів об'єкту-приймача, що викликаються
джерелом, проте в .NET існує практично загальноприйняте правило, згідно
якому функції приймача передаються два параметри:
Приклад наводився
раніше в розділі 1. При розміщенні кнопки на формі генерувалася процедура події
Click: Private Sub
Buttonl_click(Byval sender As System.Object. Byvaleas System.EventArgs) Handles Button1.Click End
Sub Параметри
мають наступний сенс:
Традиційно в
VB джерело (відправник) події не ідентифікувалося в процедурі події. Єдиним
виключенням були масиви елементів, що управляють, коли конкретний
елемент-відправник виділявся з масиву за допомогою параметра-індексу. Сенс
додаткової об'єктної змінної sender в узагальненій процедурі події VB
.NET стає очевидним, якщо пригадати, що одна процедура може обробляти
декілька подій, що поступають від різних об'єктів. Спробуйте викликати
вбудований метод Tostring в приведеній вище процедурі події:
Msgbox(sender.ToString) Результат виглядатиме так: Таким чином,
процедура-обробник може однозначно визначити, який об'єкт був джерелом
події. У даному прикладі об'єкт
події е не представляє інтересу, оскільки він не містить скільки-небудь корисної
інформації про подію. З іншого боку, в деяких ситуаціях він
може стати в нагоді. Наприклад, з об'єктної змінний класу
Mouseeventargs можна дізнатися, в якій крапці було зроблено клацання мишею. У загальному
випадку програміст визначає власні класи подій, похідні від
класу System. Eventargs і що містять будь-яку корисну інформацію про подію
(про те, як це робиться, буде розказано нижче). Також звернете увагу на
нове ключове слово Hand! es у визначенні процедури події. Як неважко здогадатися,
це ключове слово указує, які події обробляються даною процедурою.
Можливо, в даному прикладі ключове слово Handl es виглядає зайвим, проте
воно надає програмістові додаткові можливості, оскільки тепер
обробники події не зобов'язані володіти жорстко заданими іменами (фіксуються тільки
сигнатури). Отже, одна процедура може обробляти декілька подій,
для чого в кінець оголошення процедури включаються декілька секцій Handl
es. Новий підхід володіє більшою гнучкістю в порівнянні з масивами елементів, що
управляють, VB, що використалися в колишніх версіях (у VB .NET масиви
елементів не підтримуються). Хоча IDE
генерує процедури подій із стандартними іменами, в VB .NET це вже не є
обов'язковою вимогою. Якщо процедура має правильний набір параметрів і
в її заголовку присутнє ключове слово Handles, ця процедура може використовуватися
для обробки подій. Приклад: Private Sub Myclickprocedure(Byval sender As System.Object,_ Byvaleas System.EventArgs)
Handles Buttonl.Click Процедура
Myclickprocedure може обробляти подію Buttonl. Click завдяки
наявності правильних параметрів. Вона обробляє цю подію, оскільки
в заголовку вказано ключове слово Handles. Головне нововведення полягає в
явній вказівці оброблюваних подій з ключовим словом Handles. Розглянемо
інший приклад. Допустимо, попередній фрагмент був приведений до наступного вигляду: Private Sub
Myclickprocedurecbyval sender As System.Object._ Byval e As System.EventArgs) Handles Buttonl.Click. Button2.Click._ mnuthing.Click Тепер одна процедура
обробляє події відразу від двох різних кнопок і команди меню!
У Vb6 подібна універсальність була неможлива, оскільки в колишніх версіях VB
обробники подій викликалися по імені елементу. Сподіваємося, читач погодиться з
тим, що ключове слово Handl es володіє значно великим потенціалом, чим
масиви елементів, що управляють.
|
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||