Почему этот обработчик класса, прикрепленный к событию туннелирования, не срабатывает раньше обработчика экземпляра?
-
26-10-2019 - |
Вопрос
В соответствии с эта статья MSDN (среди прочих),
Обработчики классов вызываются перед любыми обработчиками прослушивателя экземпляра, которые присоединяются к экземпляру этого класса, когда маршрутизируемое событие достигает экземпляра элемента в своем маршруте.
Я совсем новичок в RoutedEvent
так что есть вероятность, что у меня есть ошибка в моем коде, но кажется, что обработчик класса прикреплен к RoutedEvent
который объявлен как RoutingStrategy.Tunnel
делает нет всегда срабатывает до того, как обработчики экземпляра будут прикреплены к одному и тому же событию.
В моем примере ниже я создал TouchButton
класс управления с туннелированием RoutedEvent
и пузырится RoutedEvent
.Я зарегистрировал обработчики классов для каждого.Затем я создал экземпляр класса в окне и обрабатывал каждое событие в коде.Я прикрепил один и тот же обработчик для события туннелирования как к элементу класса, так и к элементу класса. Grid
который содержит его.Все четыре обработчика отображают свое имя в MessageBox
чтобы вы могли четко видеть порядок выполнения.
- Предварительный просмотр экземпляра сетки
- Класс TouchButton_PreviewTouch
- Предварительный просмотр экземпляра TouchButtonTouch
- Класс TouchButton_Touch
- Экземпляр TouchButton Touch
Это означает, что если я позвоню e.Handled = true;
в классе PreviewTouch
обработчик событий, я могу остановить выполнение всех остальных обработчиков событий, кроме того, который прикреплен к обработчику событий. Grid
элемент.Так и должно быть или я где-то ошибся?В противном случае, как я могу остановить выполнение от достижения каждый обработчик событий экземпляра?
Вот класс:
public class TouchButton : Button
{
static TouchButton()
{
EventManager.RegisterClassHandler(typeof(TouchButton), PreviewTouchEvent,
new RoutedEventHandler(TouchButton_PreviewTouch), true);
EventManager.RegisterClassHandler(typeof(TouchButton), TouchEvent,
new RoutedEventHandler(TouchButton_Touch), true);
}
private static void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
{
MessageBox.Show("Class TouchButton_PreviewTouch");
}
private static void TouchButton_Touch(object sender, RoutedEventArgs e)
{
MessageBox.Show("Class TouchButton_Touch");
}
public static RoutedEvent TouchEvent = EventManager.RegisterRoutedEvent("Touch",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TouchButton));
public event RoutedEventHandler Touch
{
add { AddHandler(TouchEvent, value); }
remove { RemoveHandler(TouchEvent, value); }
}
public static RoutedEvent PreviewTouchEvent = EventManager.RegisterRoutedEvent(
"PreviewTouch", RoutingStrategy.Tunnel, typeof(RoutedEventHandler),
typeof(TouchButton));
public event RoutedEventHandler PreviewTouch
{
add { AddHandler(PreviewTouchEvent, value); }
remove { RemoveHandler(PreviewTouchEvent, value); }
}
protected override void OnClick()
{
RaiseTouchEvent();
}
private void RaiseTouchEvent()
{
RoutedEventArgs touchEventArgs = new RoutedEventArgs(PreviewTouchEvent);
RaiseEvent(touchEventArgs);
if (!touchEventArgs.Handled) RaiseEvent(new RoutedEventArgs(TouchEvent));
}
}
Вот обработчики экземпляров в коде окна:
private void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0} Instance PreviewTouch",
((FrameworkElement)sender).Name));
}
private void TouchButton_Touch(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0} Instance Touch",
((FrameworkElement)sender).Name));
}
Вот управляющий XAML:
<Grid Name="Grid" Controls:TouchButton.PreviewTouch="TouchButton_PreviewTouch">
<Controls:TouchButton x:Name="TouchButton" Width="200" Height="45" FontSize="24"
Content="Touch me" Touch="TouchButton_Touch" PreviewTouch="TouchButton_PreviewTouch" />
</Grid>
Я понимаю, что событие туннелирования обрабатывается Grid
элемент перед «туннелированием» вниз к TouchButton
element, но я думал, что обработчики классов всегда должны запускаться раньше обработчиков экземпляров.Если нет, то как я могу этого добиться?
ОБНОВЛЕНИЕ >>>
Благодаря ответу @sanguine мне удалось найти способ запретить всем обработчикам экземпляров обрабатывать это событие.Если вместо замены объявленного типа обработки класса TouchButton
с Grid
как подсказал сангвиник, я заменяю его на FrameworkElement
, тогда он поймает все FrameworkElement
- производные элементы управления.
EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent,
new RoutedEventHandler(TouchButton_PreviewTouch), true);
Решение
Статья MSDN означает: когда событие перемещения находит элемент (в дереве), который имеет как класс, так и обработчик экземпляра, он вызывает обработчик класса перед обработчиком экземпляра.Поэтому в этом случае, когда событие запускается и туннелируется извне во вход, оно сталкивается с сеткой, но у класса Grid нет обработчика класса, поэтому он просто вызывает обработчик экземпляра, используемый экземпляром «Grid».Если эта строка добавлена в кнопку переключения-
EventManager.RegisterClassHandler(typeof(Сетка), PreviewTouchEvent, new RoutedEventHandler(TouchButton_PreviewTouch), true);
тогда перед обработчиком экземпляра Grid будет вызван соответствующий обработчик класса.