- •Лабораторная работа: События и команды в wpf
- •Обзор библиотечных событий
- •Упражнение 1. Обработка событий клавиатуры
- •События мыши
- •Упражнение 2. Прослушивание событий мыши
- •Упражнение 3. Создание и прослушивание пользовательского события
- •Обработчики уровня класса
- •Добавление информации в объект аргумента события
- •Задание для Упражнения 3
- •Модель команд
- •Объекты команд
- •Библиотечные классы команд
- •Присоединение команды к источнику
- •Привязка команды к прослушивающему элементу
- •Упражнение 4. Привязка команд в разметке
- •Перекрытие функций диспетчеризации событий
- •Прямой вызов команд
- •Упражнение 5. Привязка команд в процедурном коде
- •Жесты как источники команд
- •Добавление жестов в команду
- •Способ 1
- •Способ 2
- •Способ 3
- •Добавление жестов в прослушивающий элемент
- •Упражнение 6. Разработка простого блокнота без механизма команд
- •Создание главного меню
- •Добавление иконок
- •Создание логических ресурсов
- •Создание панели инструментов, строки состояния и рабочей области
- •Замена встроенного контекстного меню
- •Назначение ресурсов неразделяемыми
- •Замена иконок на прозрачные
- •Отключение встроенных команд
- •Подключение иконки приложения
- •Распределение класса по нескольким файлам и создание вспомогательных функций
- •Размещение вариантов заголовков окна в ресурсах приложения
- •Создание заготовок обработчиков
- •Регистрация обработчиков в разметке
- •Реализация обработчиков раздела меню File
- •Обработка системной кнопки
- •Реализация части обработчиков раздела меню Edit
- •Разработка и кодирование диалогового окна Find and Replace
- •Кодирование функциональности Find and Replace в основном окне
- •Подключение функциональности Find and Replace к источникам задач
- •Разработка диалогового окна Go To
- •Применение вложенных ресурсов
- •Подключение функциональности Go To к основному окну
- •Прочие задачи
- •Принудительная перерисовка окна
- •Добавление жестов
- •Логика отключения источников задач
- •Реализация логики отключения источников задачи Save
- •Упражнение 7. Разработка простого блокнота с использованием механизма команд
- •Создание нового проекта из копии существующего
- •Краткий анализ задачи
- •Создание и привязка команд
- •Реализация логики доступности источников команд
- •Отображение позиции курсора в строке состояния
Обработчики уровня класса
Иногда может понадобиться такой обработчик пользовательского события, областью действия которого является весь класс. Для этого используется статический обработчик уровня класса. Этот обработчик вызывается каждый раз перед экземплярным обработчиком типа, как только событие доходит до объекта типа. Здесь можно принять какое-то полезное решение, например, остановить событие сразу, как только оно достигло любого первого экземпляра класса и тем самым предотвратить его попадание в экземплярный обработчик.
Для одного события можно создать несколько обработчиков уровня класса, по одному для каждого дочернего типа. Регистрация обработчиков должна выполняться только в коде, а именно в статическом конструкторе класса окна. Статический конструктор отличается тем, что он не должен иметь перегрузок, не принимает аргументы (конструктор по умолчанию) и вызывается сразу, как только объект-тип будет загружен в память (не дожидаясь создания хотя бы одного объекта-экземпляра).
Посмотрим это на простом примере, нам важен сам код регистрации обработчика уровня класса.
Добавьте в класс окна 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.
Запустите приложение, результат будет таким (для стратегии Bubble )
Результат вывода с зарегистрированным обработчиком уровня класса |
Стратегия маршрутизации: Bubble
|
