Кожен розробник, який працює в .NET, знайомий з поняттям події: це повідомлення, яке надсилається об'єктом (наприклад, елементом WPF) доповнення коду про те, що сталося щось важливе. WPF доповнює модель подій .NET новою концепцією маршрутизації подій. Маршрутизація дозволяє події виникати в одному елементі, а генеруватися в іншому: наприклад, клацання на кнопці панелі інструментів генерується в панелі інструментів, а потім в містить цю панель вікні, і тільки тоді передається на обробку коду.
Маршрутизовані події - це події з великими транспортними можливостями: вони можуть тунелюватись вниз і поширюватися бульбашками наверх по дереву елементів і по шляху запускати обробники подій. Маршрутизовані події дозволяють обробити подія в одному елементі (наприклад, в мітці), хоча воно виникло в іншому (наприклад, в зображенні всередині цієї мітки). Як і в разі властивостей залежно, маршрутизовані події можна вживати і традиційним способом - підключивши обробник подій з потрібною сигнатурою - але все одно необхідно розуміти принципи їх роботи, щоб задіяти всі їх можливості.
Маршрутизація подій дає можливість писати лаконічний і зрозумілий код, який може обробляти події в найбільш зручному для цього місці. Вона необхідна також для роботи з моделлю вмісту WPF, що дозволяє створювати прості елементи (наприклад, кнопки) з десятків окремих інгредієнтів, кожен з яких має свій власний набір подій.
Модель подій WPF дуже схожа на модель властивостей WPF. Як і властивості залежно, маршрутизовані події представляються статичними полями, доступними тільки для читання, які реєструються в статичному конструкторі і оформляються у вигляді стандартного визначення події .NET.
Наприклад, WPF-клас Button пропонує знайоме подія Click, що є нащадком абстрактного класу ButtonBase. Нижче показано, як визначається і реєструється цю подію:
Властивості залежності реєструються за допомогою методу DependencyProperty.Register (), а для реєстрації маршрутизованих подій призначений метод EventManager.RegisterRoutedEvent (). При реєстрації події потрібно вказати ім'я події, тип маршрутизації (про це трохи пізніше), делегат, який визначає синтаксис обробника події (в даному прикладі це RoutedEventHandler), і клас, до якого належить подія (в даному прикладі ButtonBase).
Як правило, маршрутизовані події упаковуються в звичайні події .NET, щоб зробити їх доступними для всіх мов .NET. Оболонка події додає і видаляє зареєстровані викликають об'єкти за допомогою методів AddHandler () і RemoveHandler (), які визначені в базовому класі FrameworkElement і успадковуються кожним елементом WPF.
Як і в разі властивостей залежності, визначення маршрутизованих подій можна спільно використовувати декількома класами. Наприклад, подія MouseUp використовують два базових класи: UIElement (початкова точка для звичайних елементів WPF) і ContentElement (початкова точка для елементів контенту - окремих частин вмісту, які можуть поміщатися в документі потоку). Подія MouseUp визначено в класі System.Windows.Input.Mouse. Класи UIElement і ContentElement просто використовують його за допомогою методу RoutedEvent.AddOwner ():
Генерація маршрутизациї події
Звичайно, як і будь-яка подія, що визначає клас повинен десь згенерувати маршрутизуються подія. Де саме - це вже деталі реалізації. Однак слід пам'ятати, що ваше подія не порушується через традиційну оболонку подій .NET. Замість цього використовується метод RaiseEvent (), успадковані кожним елементом від класу UIElement. Нижче представлений відповідний код класу ButtonBase:
Метод RaiseEvent () відповідає за генерацію події для кожного викликає об'єкта, який був зареєстрований за допомогою методу AddHandler (). Оскільки цей метод є загальнодоступним, зухвалим об'єктів надається вибір: вони можуть зареєструватися безпосередньо, за допомогою методу AddHandler (), або скористатися оболонкою події.
У будь-якому випадку вони будуть повідомлені про виклик методу RaiseEvent (). Всі події WPF дотримуються знайомого вам умови про сигнатури подій, існуючого в .NET. Перший параметр кожного обробника події містить посилання на об'єкт, який згенерував подія (відправник). Другий параметр - об'єкт EventArgs, який об'єднує всі додаткові деталі, які можуть знадобитися.
Наприклад, подія MouseUp надає об'єкт MouseEventArgs, який показує, яка кнопка миші була натиснута при виникненні події.
У додатках Windows Forms для багатьох подій зазвичай застосовувався базовий клас EventArg, якщо їм не було потрібно передавати додаткову інформацію. У додатках WPF ситуація інша, оскільки в них підтримується модель маршрутизованих подій.
Якщо події не потрібно посилати будь-яку додаткову інформацію, то в WPF воно використовує клас RoutedEventArgs. який містить деякі відомості про маршрутизації події. Якщо події потрібно передати додаткову інформацію, воно використовує більш спеціалізований об'єкт, породжений від RoutedEventArgs. Оскільки кожен клас аргументу події WPF породжений від RoutedEventArgs, кожен обробник події WPF має доступ до інформації про маршрутизації події.