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

StackOverflow https://stackoverflow.com/questions/9320916

Вопрос

В соответствии с эта статья MSDN (среди прочих),

Обработчики классов вызываются перед любыми обработчиками прослушивателя экземпляра, которые присоединяются к экземпляру этого класса, когда маршрутизируемое событие достигает экземпляра элемента в своем маршруте.

Я совсем новичок в RoutedEventтак что есть вероятность, что у меня есть ошибка в моем коде, но кажется, что обработчик класса прикреплен к RoutedEvent который объявлен как RoutingStrategy.Tunnel делает нет всегда срабатывает до того, как обработчики экземпляра будут прикреплены к одному и тому же событию.

В моем примере ниже я создал TouchButton класс управления с туннелированием RoutedEvent и пузырится RoutedEvent.Я зарегистрировал обработчики классов для каждого.Затем я создал экземпляр класса в окне и обрабатывал каждое событие в коде.Я прикрепил один и тот же обработчик для события туннелирования как к элементу класса, так и к элементу класса. Grid который содержит его.Все четыре обработчика отображают свое имя в MessageBox чтобы вы могли четко видеть порядок выполнения.

  1. Предварительный просмотр экземпляра сетки
  2. Класс TouchButton_PreviewTouch
  3. Предварительный просмотр экземпляра TouchButtonTouch
  4. Класс TouchButton_Touch
  5. Экземпляр 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 будет вызван соответствующий обработчик класса.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top