Согласно этой статье MSDN (среди прочих),
Обработчики класса вызываются до любых обработчиков прослушивателей экземпляров, которые присоединены к экземпляру этого класса, всякий раз, когда маршрутизируетсясобытие достигает экземпляра элемента на своем маршруте.
Я довольно новичок в RoutedEvent
s, поэтому есть вероятность, что в моем коде есть ошибка, но кажется, что обработчик классаприкрепленный к RoutedEvent
, объявленному как RoutingStrategy.Tunnel
, не всегда срабатывает до того, как обработчики экземпляра присоединятся к тому же событию.
В моем примере ниже я создал TouchButton
класс управления с туннелированием RoutedEvent
и барботированием RoutedEvent
.Я зарегистрировал обработчики классов для каждого.Затем я создал экземпляр класса в окне и обработал каждое событие в коде позади.Я подключил один и тот же обработчик для события туннелирования как к элементу класса, так и к Grid
, который его содержит.Все четыре обработчика отображают свое имя в MessageBox
, так что вы можете четко видеть порядок выполнения.
- Grid Instance PreviewTouch
- Класс TouchButton_PreviewTouch
- TouchButton Instance PreviewTouch
- Класс TouchButton_Touch
- TouchButton Instance 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
элемент, но я думал, что обработчики класса всегда должны запускаться перед обработчиками экземпляра.Если нет, то как мне этого добиться?
ОБНОВЛЕНИЕ >>>
Благодаря ответу @ sanguine мне удалось найти способ остановить обработку всех обработчиков экземпляровсобытие.Если вместо того, чтобы заменить объявленный тип обработки класса TouchButton
на Grid
, как предложил sanguine, я заменю его на FrameworkElement
, тогда он перехватит все FrameworkElement
производные элементы управления.
EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent,
new RoutedEventHandler(TouchButton_PreviewTouch), true);