Почему этот обработчик класса, подключенный к событию туннелирования, не запускается перед обработчиком экземпляра? - PullRequest
1 голос
/ 17 февраля 2012

Согласно этой статье MSDN (среди прочих),

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

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

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

  1. Grid Instance PreviewTouch
  2. Класс TouchButton_PreviewTouch
  3. TouchButton Instance PreviewTouch
  4. Класс TouchButton_Touch
  5. 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);

1 Ответ

0 голосов
/ 17 февраля 2012

Статья MSDN означает - Когда событие обхода находит элемент (в дереве), который имеет как класс, так и обработчик экземпляра, то он вызывает обработчик класса перед обработчиком экземпляра.Следовательно, в этом случае, когда событие запускается и туннелируется изнутри внутрь, оно встречается с сеткой, но класс Grid не имеет никакого обработчика класса, поэтому он просто вызывает обработчик экземпляра, используемый экземпляром "Grid".Если эта строка добавлена ​​в переключателе -

EventManager.RegisterClassHandler (typeof ( Grid ), PreviewTouchEvent, новый RoutedEventHandler (TouchButton_PreviewTouch), true);

, затем до Grid'sобработчик экземпляра, будет вызван соответствующий обработчик класса.

...