Главная » WPF » События дополнительный механизм маршрутизации WPF

0

В WPF события ведут себя точно так же, как в любой другой библиотеке клас

сов, входящей в состав .NET. Каждый объект предоставляет набор событий, на ко

торые можно подписаться, определив соответствующий делегат. Мы уже отмечали, что в WPF имеется дополнительный механизм  маршрутизации событий, который позволяет  им распространяться вверх по дереву элементов.  Существует  три вида маршрутизации событий: прямая,  всплытие  (bubbling) и туннелирование (tunnel ing). Прямые события – это простые события, возникающие от одиночного источ ника, они почти идентичны  стандартным  событиям .NET с тем отличием, что реги стрируются  в системе маршрутизации событий  WPF1. Некоторые средства  плат формы (например, триггеры)  требуют, чтобы событие было явно зарегистрировано.

Всплывающие и туннельные события – две стороны одной медали: туннельные

события продвигаются  от корня дерева к целевому элементу,  а всплывающие – в обратном направлении. Обычно эти два вида событий встречаются попарно, причем туннельная версия имеет префикс Preview. Большинство событий ввода (от клави атуры, от мыши и от пера) имеют как туннельную, так и всплывающую версии, нап ример: MouseRightButtonDown и PreviewMouseRightButtonDown, соответственно.

Написав  небольшой пример, в котором создается иерархия  элементов  и обра батываются  некоторые  события, мы сможем увидеть, как соотносятся между со бой всплывающие и туннельные события. Ниже создается окно с группирующей рамкой и двумя кнопками:

<Window …

PreviewMouseRightButtonDown=’WindowPreviewRightButtonDown’ MouseRightButtonDown=’WindowRightButtonDown’

<GroupBox PreviewMouseRightButtonDown=’GroupBoxPreviewRightButtonDown’ MouseRightButtonDown=’GroupBoxRightButtonDown’

<StackPanel>

<Button>One</Button>

<Button PreviewMouseRightButtonDown=’ButtonTwoPreviewRightButtonDown’ MouseRightButtonDown=’ButtonTwoRightButtonDown’

> Two

</Button>

</StackPanel>

</GroupBox>

</Window>

В обработчике  каждого события мы можем вывести его имя:

void ButtonTwoPreviewRightButtonDown(object sender, MouseButtonEventArgs e) {

Debug.WriteLine(«ButtonTwo PreviewRightButtonDown»);

}

1  Система маршрутизации отвечает в WPF за продвижение событий по дереву элементов. Боль% шая часть этой системы скрыта, видимы лишь небольшие островки, например: EventManager, RegisterRoutedEvent.

void ButtonTwoRightButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine(«ButtonTwo RightButtonDown»);

}

void GroupBoxPreviewRightButtonDown(object sender, MouseButtonEventArgs e) {

Debug.WriteLine(«GroupBox PreviewRightButtonDown»);

}

void GroupBoxRightButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine(«GroupBox RightButtonDown»);

}

void WindowPreviewRightButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine(«Window PreviewRightButtonDown»);

}

void WindowRightButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine(«Window RightButtonDown»);

}

Во время работы этой программы события возникают  в следующем порядке:

1.  Window PreviewMouseRightButtonDown.

2.  Window PreviewMouseRightButtonDown.

3.  GroupBox  PreviewMouseRightButtonDown.

4.  Button PreviewMouseRightButtonDown.

5.  Button MouseRightButtonDown.

6.  GroupBox  MouseRightButtonDown.

7.  Window MouseRightButtonDown.

В качестве еще одной иллюстрации на рис. 7.3 показаны две фазы маршрутизации событий. Любое поведение элемента управления  по умолчанию должно быть реали зовано во всплывающей версии события. Например, элемент Button создает событие Click в обработчике  события  MouseLeftButtonUp. Этот принцип  неиспользования Preview событий позволяет разработчикам приложений задействовать последние для вставки собственной логики или отмены принятого по умолчанию поведения элемен та. В любой точке процедуры мы можем присвоить  значение true свойству Handled аргумента события и тем самым предотвратить вызов последующих обработчиков.

Чтобы увидеть, как этот механизм работает, подпишемся на событие PreviewMouseLeftButtonDown объекта Window.  Присвоив  свойству Handled значение true, мы сможем проигнорировать щелчок по любому элементу:

public Window1() {

this.PreviewMouseRightButtonDown += WindowPreviewRightButtonDown;

}

void WindowPreviewRightButtonDown(object sender, MouseButtonEventArgs e) {

e.Handled = true;

}

Handled – одно из нескольких  интересных  свойств, общих для всех маршру тизируемых событий. Аргумент, передаваемый при возникновении любого тако го события, – экземпляр класса, производного  от RoutedEventArgs:

public class RoutedEventArgs : EventArgs {

public bool Handled { get; set; }

public object OriginalSource { get; }

public RoutedEvent RoutedEvent { get; set; }

public object Source { get; set; }

}

Свойства  OriginalSource и Source оказываются весьма полезны. Source ссыла ется на отправителя события, то есть на объект, к которому мы присоединили об работчик. А OriginalSource – это объект, в котором возникло  событие, то есть ис тинный  источник.  В предыдущих  примерах  истинным  источником был объект ButtonChrome – визуальный элемент, включенный в шаблон кнопки. Поскольку события  мыши относятся  к числу физических, их истинным  источником всегда является элемент, над которым находилась мышь в момент возникновения собы тия. Истинным же источником большинства семантических событий, того же Click, будет элемент, создавший  событие.

Чтобы это стало очевидно, напишем код, который будет реагировать на события нажатия и отпускания кнопки мыши, а также на щелчки. При той же структуре де рева элементов, что и выше, мы получим следующую последовательность событий:

Window PreviewMouseLeftButtonDown,Source=Button,Original=ButtonChrome GroupBox PreviewMouseLeftButtonDown,Source=Button,Original=ButtonChrome ButtonTwo PreviewMouseLeftButtonDown,Source=Button,Original=ButtonChrome ButtonTwo Click, Source=Button, OriginalSource=Button

GroupBox Click, Source=Button, OriginalSource=Button

Window Click, Source=Button, OriginalSource=Button

Обратите внимание, что событие MouseLeftButtonDown отсутствует. Связано это с тем, что элемент  Button сам обрабатывает  его, чтобы впоследствии возбу дить событие Click.

Туннелирование и всплытие прекрасно работают для таких встроенных в каждый элемент управления событий, как события мыши. Однако туннелироваться и всплы вать может любое событие (как показывает  предыдущий  пример с Click).Чтобы обеспечить и туннелирование, и всплытие, WPF поддерживает присоединенные со бытия. Подобно тому, как система свойств позволяет присоединять свойства к любо му элементу, мы можем присоединить к любому элементу и обработчик событий.

Если мы хотим получать  извещения о нажатии  любой кнопки  в окне, доста точно просто вызвать  метод AddHandler. У каждого события в WPF имеется свойство  типа RoutedEvent, которое во время исполнения ссылается  на объект источник.  Чтобы  присоединить обработчик,  мы  передаем  методу  AddHandler объект RoutedEvent и делегат, который необходимо вызвать:

this.AddHandler(Button.ClickEvent,

(RoutedEventHandler)delegate { MessageBox.Show(«Clicked»); });

WPF расширяет  базовую модель событий .NET, добавляя систему маршрути зации событий, которая  учитывает  композицию элементов.  Все остальные  сред ства обработки действий построены на базе этой модели маршрутизации.

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии