Главная » Silverlight » Маршрутизация событий

0

Каждый разработчик .NET хорошо знаком с концепцией событий — своего рода сигналов, генерируемых объектами (например, элементами Silverlight) и передаваемых коду, чтобы сообщить ему, что нечто произошло. В технологии WPF модель событий .NET дополнена новой концепцией — маршрутизируемыми событиями, которые могут происходить в одних элементах, а генерироваться в других. Например, при щелчке на фигуре сначала генерируется событие фигуры, после этого событие контейнера, содер­жащего фигуру, затем событие страницы, содержащей контейнер, — и все это еще до того, как событие будет обработано кодом приложения.

В Silverlight часть модели маршрутизируемых событий заимствована из технологии WPF в существенно упрощенной форме. В технологии WPF поддерживается несколько типов маршрутизируемых событий, а в Silverlight доступны только поднимающиеся со­бытия (bubbling events), которые переходят вверх по дереву иерархии от вложенных элементов через вложенные контейнеры вплоть до сущности самого высокого уровня — страницы Silverlight. Более того, поднимающиеся события Silverlight связаны всего лишь с несколькими операциями с клавиатурой и мышью (например, MouseMove и KeyDown) и поддерживаются всего лишь несколькими низкоуровневыми элементами управле­ния. В элементах более высокого уровня поднимающиеся события не поддерживаются. Многие полезные события (например, Click) не маршрутизируются. Кроме того, марш­рутизируемое событие невозможно определить в пользовательском элементе управления.

Базовые события элементов

Элементы наследуют свой базовый набор событий от двух классов: UlElement и FrameworkElement. Как показано на рис. 4.2, все элементы Silverlight являются произ­водными от этих двух элементов.

Рис. 4.4. При щелчке приложение выводит список сгенерированных событий

Подъем события можно наблюдать, подключив обработчики к нескольким элемен­там. Событие перехватывается на разных уровнях, и последовательность перехвата вы­водится в списке. На рис. 4.4 показан список сразу после щелчка на изображении, рас­положенном в кнопке. Каждый элемент списка содержит имя объекта sender, сгенери­ровавшего событие. Из рис. 4.4 видно, что событие MouseLeftButtonDown сначала гене­рируется в изображении, затем на панели StackPanel, после чего перехватывается кноп­кой, которая обрабатывает его. Кнопка не генерирует событие MouseLeftButtonDown, поэтому оно не поднимается в контейнер Grid, содержащий кнопку.

В тестовой форме изображение и каждый элемент, расположенный над ним в дереве иерархии, подключены к одному и тому же обработчику — методу SomethingClicked (). Ниже приведена разметка тестовой формы.

<UserControl х:Class="RoutedEvents.EventBubbling" xmlns="http: //schemas .microsoft. com/winfx/2006/xaml/

presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid Margin="3" MouseLeftButtonDown="SomethingClicked"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition>       •

<RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions>

<Button Margin="5" Grid.Row="0"

MouseLeftButtonDown="SomethingClicked"> <StackPanel MouseLeftButtonDown="SomethingClicked"> <TextBlock Margin="3"

MouseLeftButtonDown="SomethingClicked" Hori zontalAlignment="Center"

Техt="Кнопка с изображением и TeKCT0M"></TextBl0Ck> <Image Source="happyface.jpg" Stretch="None" MouseLeftButtonDown="SomethingClicked"></Image> <TextBlock Margin="3" HorizontalAlignment="Center" MouseLeftButtonDown="SomethingClicked" Text="Eщe немного текста. .. "></TextBlock> </StackPanel> </Button>

<ListBox Grid.Row="l" Margin="5" x:Name="lstMessages"> </ListBox>

<Button Grid.Row="3" Margin="5" Padding="3"

x:Name="cmdClear" Click="cmdClear_Click" Content="Очистить список"> </Button>

</Grid>

</UserControl>

Метод SomethingClicked () добавляет имя объекта sender в список, чтобы было вид­но, где сгенерировано событие.

protected int eventCounter = 0;

private void SomethingClicked(object sender,

MouseButtonEventArgs e)

{                                                                      7

eventCounter++;

string message = "#" + eventCounter.ToStringO + ":\r\n" + " Sender: " + sender.ToStringO + "\r\n";

IstMessages.Items.Add(message) ;

}

private void cmdClear_Click(object sender, RoutedEventArgs e)

{

IstMessages.Items.Clear() ;

}

В обработчиках событий типа MouseLeftButtonDown параметр sender всегда содер­жит ссылку на последнее звено в цепи событий. Например, если событие поднялось от изображения до панели StackPanel, параметр sender содержит ссылку на объект

StackPanel.

В некоторых случаях желательно выяснить, где событие произошло, а не какой объ­ект передал его. Это можно сделать с помощью параметра е, содержащего свойство Source, которое в свою очередь содержит ссылку на элемент, в котором произошло событие. События клавиатуры происходят в элементе управления, имеющем фокус в мо­мент нажатия клавиши. События мыши происходят в самом высокоуровневом элемен­те управления, на который в момент щелчка был наведен указатель. Однако свойство Source передает еще и дополнительную информацию. Например, если щелкнуть в пу­стом пространстве, заполненном фоном кнопки, свойство Source предоставит ссылку на объект Shape или Path, нарисовавший ту часть фона, на которой был выполнен щелчок.

Кроме свойства Source, объект е поднимающегося события предоставляет булево свойство Handled, позволяющее отменить событие. Например, если при обработке со­бытия MouseLeftButtonDown панели StackPanel присвоить свойству Handled значение true, панель не передаст событие MouseLeftButtonDown дальше. В результате при щелч­ке на панели (или на любом вложенном в нее элементе) событие MouseLeftButtonDown не достигнет кнопки и событие Click не будет сгенерировано. Это можно использовать при создании пользовательских элементов управления, когда нужно обработать только щелчок на кнопке и не вовлекать элементы более высоких уровней.

Примечание. В технологии WPF существует "лазейка", позволяющая коду получать события, отмеченные как обработанные (обычно они игнорируются). Технология Silverlight не предоставляет такой возможности.

Перемещение указателя

Кроме событий щелчка (MouseLeftButtonDown и MouseLeftButtonUp), Silverlight предоставляет и другие события мыши, генерируемые при перемещении указателя. Событие MouseEnter генерируется, когда указатель входит в область элемента (пере­секает границу), событие MouseLeave — когда указатель выходит из области элемента, а событие MouseMove — при каждом перемещении указателя (при непрерывном переме­щении генерируются сотни событий MouseMove в секунду).

Все события перемещения указателя передают в код одну и ту же информацию по­средством объекта MouseEventArgs. Объект содержит метод GetPosition (), возвраща­ющий координаты указателя относительно заданного элемента. Ниже приведен пример вывода на экран координат указателя.

private void MouseMoved(object sender, MouseEventArgs e)

{

Point pt = e.GetPosition(this); lbllnfo.Text = String.Format("Указатель находится в точке ({0},{1})" +

" в системе координат страницы", pt.X, pt.Y);

}

В данном примере координаты отсчитываются от верхнего левого угла страницы (под строкой заголовка браузера).

Совет. Чтобы получить координаты указателя относительно контейнера, свойству Background должно быть присвоено значение, отличное от null.

Источник: Мак-Дональд, Мэтью. Silverlight 3 с примерами на С# для профессионалов. : Пер. с англ. —- М. : ООО «И.Д. Вильяме», 2010. — 656 с. : ил. — Парал. тит. англ.

По теме:

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