Обработчики уровня класса

Иногда может понадобиться такой обработчик пользовательского события, областью действия которого является весь класс. Для этого используется статический обработчик уровня класса. Этот обработчик вызывается каждый раз перед экземплярным обработчиком типа, как только событие доходит до объекта типа. Здесь можно принять какое-то полезное решение, например, остановить событие сразу, как только оно достигло любого первого экземпляра класса и тем самым предотвратить его попадание в экземплярный обработчик.

Для одного события можно создать несколько обработчиков уровня класса, по одному для каждого дочернего типа. Регистрация обработчиков должна выполняться только в коде, а именно в статическом конструкторе класса окна. Статический конструктор отличается тем, что он не должен иметь перегрузок, не принимает аргументы (конструктор по умолчанию) и вызывается сразу, как только объект-тип будет загружен в память (не дожидаясь создания хотя бы одного объекта-экземпляра).

Посмотрим это на простом примере, нам важен сам код регистрации обработчика уровня класса.

  • Добавьте в класс окна Window1 следующий код (теперь листинг файла Window1.xaml.cs приводится полностью)
using System;using System.Collections.Generic;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes; namespace UserEvents{ public partial class Window1 : Window { /* static Window1() { // Добавить владельца события ????? MyButton.TapEvent.AddOwner(typeof(FrameworkElement)); } */ // Статический конструктор (без аргументов и перегрузок) static Window1() { // Зарегистрировать обработчик уровня любого класса дерева, который // сработает перед всеми обработчиками экземпляра этого класса EventManager.RegisterClassHandler( typeof(Window1), MyButton.TapEvent, new RoutedEventHandler(SuperMethod1)); EventManager.RegisterClassHandler( typeof(System.Windows.Controls.Primitives.UniformGrid), MyButton.TapEvent, new RoutedEventHandler(SuperMethod2)); } // Обработчик уровня класса static void SuperMethod1(object sender, RoutedEventArgs e) { String typeName = sender.GetType().Name; System.Diagnostics.Debug.WriteLine( String.Format("{0}) {1}: Суперобработчик события Tab", ++MyButton.count, typeName)); } // Обработчик уровня класса static void SuperMethod2(object sender, RoutedEventArgs e) { String typeName = sender.GetType().Name; System.Diagnostics.Debug.WriteLine( String.Format("{0}) {1}: Суперобработчик события Tab", ++MyButton.count, typeName)); } // Конструктор экземпляра public Window1() { InitializeComponent(); // Динамический способ присоединения обработчиков nWindow1.AddHandler(MyButton.TapEvent, new RoutedEventHandler(this.nWindow1_Tap)); nDockPanel.AddHandler(MyButton.TapEvent, new RoutedEventHandler(this.nDockPanel_Tap)); } private void MyButton_Tap(object sender, RoutedEventArgs e) { this.ShowTap(sender, e); } private void UniformGrid_Tap(object sender, RoutedEventArgs e) { this.ShowTap(sender, e); } private void Grid_Tap(object sender, RoutedEventArgs e) { this.ShowTap(sender, e); } private void nDockPanel_Tap(object sender, RoutedEventArgs e) { this.ShowTap(sender, e); } private void nWindow1_Tap(object sender, RoutedEventArgs e) { this.ShowTap(sender, e); } void ShowTap(object obj, RoutedEventArgs args) { if (MyButton.count == 0) { System.Diagnostics.Debug.WriteLine( String.Format("\n\t Стратегия маршрутизации: {0}", args.RoutedEvent.RoutingStrategy)); } String typeName = obj.GetType().Name; System.Diagnostics.Debug.WriteLine( String.Format("{0}) {1}: Наблюдаю событие Tap", ++MyButton.count, typeName)); } }}

Закомментированный код оставлен для размышлений по поводу метода AddOwner(). Как и где его применять, я так и не смог разобраться по MSDN.