1

根据这篇 MSDN 文章(除其他外),

每当路由事件到达其路由中的元素实例时,在附加到该类实例的任何实例侦听器处理程序之前调用类处理程序。

我对RoutedEvents 很陌生,所以我的代码中可能有错误,但似乎附加到 a 的类处理程序RoutedEvent被声明为RoutingStrategy.Tunnel并不总是在附加到同一事件的实例处理程序之前触发。

在下面的示例中,我创建了一个TouchButton带有隧道RoutedEvent和冒泡的控件类RoutedEvent。我已经为每个注册了类处理程序。然后,我在窗口中创建了该类的一个实例,并在后面的代码中处理每个事件。Grid我在类元素和包含它的元素上都为隧道事件附加了相同的处理程序。所有四个处理程序都以 a 显示它们的名称,MessageBox因此您可以清楚地看到执行顺序。

  1. 网格实例 PreviewTouch
  2. 类 TouchButton_PreviewTouch
  3. TouchButton 实例 PreviewTouch
  4. 类 TouchButton_Touch
  5. TouchButton 实例触摸

这意味着如果我调用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 的回答,我设法找到了一种方法来阻止所有实例处理程序处理事件。如果不是像 sanguine 建议的那样替换声明的类处理类型,而是将其替换为TouchButton,那么它将捕获所有派生控件。GridFrameworkElementFrameworkElement

EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent, 
new RoutedEventHandler(TouchButton_PreviewTouch), true);
4

1 回答 1

0

MSDN文章的意思是——当一个遍历事件找到一个同时提供类和实例处理程序的元素(在树中)时,它会在实例处理程序之前调用类处理程序。因此,在这种情况下,当事件被触发并从外向内传输时,它会遇到网格,但网格类没有任何类处理程序,因此它仅调用“网格”实例使用的实例处理程序。如果在切换按钮中添加了此行 -

EventManager.RegisterClassHandler(typeof( Grid ), PreviewTouchEvent, new RoutedEventHandler(TouchButton_PreviewTouch), true);

然后在 Grid 的实例处理程序之前,将调用相应的类处理程序。

于 2012-02-17T10:44:50.063 回答