为什么在实例处理程序之前没有附加到隧道事件的类处理程序?

时间:2012-02-16 23:51:11

标签: wpf class handler instance routedevent

根据this MSDN article(以及其他),

  

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

我对RoutedEvent很新,所以我的代码中可能存在错误,但似乎附加到RoutedEvent的类处理程序被声明为{在附加到同一事件的实例处理程序之前, not 总是会触发。

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

  1. 网格实例PreviewTouch
  2. Class TouchButton_PreviewTouch
  3. TouchButton Instance PreviewTouch
  4. Class TouchButton_Touch
  5. TouchButton Instance Touch
  6. 这意味着如果我在类MessageBox事件处理程序中调用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));
        }
    }
    

    这是控件XAML:

    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));
    }
    

    我确实理解隧道事件是由<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元素之前处理的,但我认为类处理程序总是应该在实例处理程序之前触发。如果没有,我怎么能实现这个目标?

    更新&gt;&gt;&gt;

    感谢@ sanguine的回答,我设法找到一种方法来阻止所有实例处理程序处理事件。如果不是将TouchButton的声明类处理类型替换为TouchButton作为乐观建议,而是将其替换为Grid,那么它将捕获所有FrameworkElement派生的控件。< / p>

    FrameworkElement

1 个答案:

答案 0 :(得分:0)

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

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

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