Туннелируемые события

88

Туннелируемые события (которые все начинаются с префикса Preview, например, PreviewMouseDown) спускаются вниз от элемента верхнего уровня во вложенные контексты дерева объектов. В общем случае, каждому пузырьковому событию в библиотеках базовых классов WPF соответствует связанное туннелируемое событие, которое инициируется перед его пузырьковым дополнением. Например, перед инициацией пузырькового события MouseDown сначала происходит туннелируемое событие PreviewMouseDown.

Обработка туннелируемых событий выглядит как обработка любых других событий; вы просто назначаете имя обработчика события в XAML (или, если необходимо, используете соответствующий синтаксис обработки событий C# в файле кода) и реализуете этот обработчик в файле кода.

Туннелируемые события работают так же, как и пузырьковые, но в обратном направлении. Например, если бы событие MouseUp было туннельным (а это не так), то при щелчке на изображении в примере с меткой событие MouseUp возникло бы сначала в окне, затем в элементе Grid, затем в StackPanel и так далее до достижения источника, т.е. изображения в метке.

WPF обычно определяет события попарно. Это означает, что если имеется пузырьковое событие MouseUp, то, скорее всего, существует и туннелируемое событие PreviewMouseUp. Туннелируемые событие всегда возникает перед пузырьковым событием, как показано на рисунке:

События WPF

Интересный момент: если пометить туннелируемое событие как обработанное, то пузырьковое событие не возникнет. Это связано с тем, что оба события совместно используют один и тот же экземпляр класса RoutedEventArgs.

Туннелируемые события полезны, если нужно выполнить предварительную обработку, связанную с определенными нажатиями клавиш, или отфильтровать некоторые события мыши.

Будьте аккуратны с пометкой туннелируемого события как обработанного. В зависимости от конструкции управляющего элемента, это может помешать ему обработать собственное (соответствующее пузырьковое) событие, чтобы выполнить какое-то действие или обновить свое состояние.

Понятно, что разные стратегии маршрутизации влияют на способ использования событий. А как определить, какой тип маршрутизации использует данное событие?

С туннелируемыми событиями все просто. В соответствии с соглашениями, принятыми в .NET, туннелируемое событие всегда начинается со слова Preview (например, PreviewKeyDown). Однако похожего механизма различения пузырьковых и прямых событий не существует. Разработчикам, применяющим WPF, лучше всего найти описание события в документации по WPF. В разделе "Routed Event Information" указываются статическое поле события, тип маршрутизации и сигнатура события.

Эту же информацию можно получить программным способом, проверив статическое поле для события. Например, свойство ButtonBase.ClickEvent.RoutingStrategy содержит перечислимое значение, которое сообщает, какой тип маршрутизации использует событие Click.

Итак, почему же события WPF обычно идут парами (одно туннелируемое и одно пузырьковое)? Ответ заключается в том, что за счет предварительного отслеживания событий вы получаете возможность выполнять любую специфическую логику (проверку достоверности данных, отключение пузырьковых действий и т.д.), прежде чем будет инициирован пузырьковый аналог события. Для примера предположим, что имеется элемент TextBox, который должен допускать ввод только числовых данных. В обработчике события PreviewKeyDown, если пользователь ввел какие-то нечисловые данные, можно отменить пузырьковое событие, установив свойство Handled в true.

При построении специального элемента управления, который содержит специальные события, событие можно написать таким образом, чтобы оно могло распространяться, как пузырьковое (или туннелируемое) по дереву XAML. Если интересно, загляните в раздел "Routed Events Overview" ("Обзор маршрутизируемых событий") документации .NET Framework 4.0 SDK. Там вы найдете множество полезных подсказок.

Пройди тесты
Лучший чат для C# программистов