难倒 - 在WPF中将路径冒泡到顶部窗口 - 如何在任何地方捕获!

时间:2010-03-04 12:53:37

标签: c# wpf

这方面的文献非常糟糕 - 我想要做的就是从我已定义的控件中冒出一个事件,但是从代理控制器类中动态创建(希望这不会导致问题)。该控件是一个PopUp。

public static readonly RoutedEvent weClosed = EventManager.RegisterRoutedEvent("TIMBOO", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FixedTaskbarNotifier));


    // Provide CLR accessors for the event
    public event RoutedEventHandler TIMBOO
    {
        add { AddHandler(weClosed, value); }
        remove { RemoveHandler(weClosed, value); }
    }

    // This method raises the Tap event
    void RaiseTapEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(weClosed);
        RaiseEvent(newEventArgs);}


    protected override void OnClosed(EventArgs e)
    {
        //TO DO - rearrange current open windows - fire event?
        Log.Instance.Info("Clean up Window");
        RaiseTapEvent(); This is called on close but nothing fires ..
                }

我希望能在某个地方捕捉到这个事件 - 甚至在我的父窗口或更高的视觉树上。这引用了一个控制器,它包含了通知控件列表 - 我知道哪一个被关闭了,我可以重新编辑/重新绘制任何仍然通过控制器激活的其他控件,但是如何捕获? 谢谢!

2 个答案:

答案 0 :(得分:5)

我同意,关于MSDN上冒泡/隧道的文档并不是很好。

我发现这篇MSDN杂志文章"Understanding Routed Events and Commands In WPF"更能解释冒泡事件。

查找“事件路由”部分,复制粘贴在下面:

  

事件路由

     

了解一点   关于逻辑和可视树是   很重要,因为路由事件得到了   主要基于视觉路由   树。路由事件支持a   Bubble,Tunnel或者的RoutingStrategy   直接

     

泡泡是最常见的   意味着一个事件会冒泡   (传播)来自的视觉树   源元素,直到它有   已经处理或它到达根   元件。这允许你处理一个   在一个物体上的事件进一步上升   来自源的元素层次结构   元件。例如,您可以附加   一个Button.Click处理程序   包含Grid元素而不是   直接在按钮上。气泡   事件只有表明的名称   他们的行动(例如,MouseDown)。

     

隧道事件进入另一个   方向,从根开始   元素和遍历   元素树,直到它们被处理或   到达源元素   事件。这允许上游元素   拦截事件并处理它   在事件到达源头之前   元件。隧道事件有他们的   以Preview by为前缀的名称   约定(例如PreviewMouseDown)。

     

直接事件的行为与正常情况相同   .NET Framework中的事件。唯一的   该事件的潜在处理程序是   与之挂钩的代表   事件。

     

通常是隧道事件   在那里为特定事件定义   是一个相应的泡沫事件。在   那种情况下,隧道事件会发生   首先,从根开始   一路走到源头   寻找处理程序的元素。一旦它   已经处理或已达到   源元素,泡泡事件是   被解雇了,一路上升   源元素和寻找一个   处理程序。泡泡或隧道事件确实如此   不要因为一个而停止它的路由   调用事件处理程序。如果你想   停止冒泡或隧道   过程,您将事件标记为已处理   在您的事件处理程序中使用该事件   你传递的论据:

private void OnChildElementMouseDown(object sender, MouseButtonEventArgs e) { e.Handled = true; }
  

一旦你的处理程序将事件标记为   处理后,它不会被提升到任何地方   更多的处理程序。嗯,那只是   部分正确。实际上,事件   路由继续在幕后,   你可以明确地挂钩事件   代码中的处理程序覆盖   UIElement.AddHandler方法   有效地增加了一面旗帜   说,“即使事件发生,也请打电话给我   被标记为已处理。“你指定   那个标志有一个像这样的电话   以下内容:

m_SomeChildElement.AddHandler(UIElement.MouseDownEvent, (RoutedEventHandler)OnMouseDownCallMeAlways,true);
  

AddHandler的第一个参数是   你想要处理的RoutedEvent。   第二个是代表   事件处理方法(需要   拥有正确的签名   事件的代表)。第三个参数   表明你是否想成为   即使另一个处理程序有通知   将事件标记为已处理。该   您调用AddHandler的元素   是一个值得关注的人   在路由期间流动的事件。

希望这有帮助。

答案 1 :(得分:3)

在您的父级或您想要处理它的任何地方,您应该只需通过声明它所声明的类和事件名称来处理该事件。在您的情况下,在您的窗口声明中,执行:

<Window ... FixedTaskbarNotifier.TIMBOO="<EventHandlerName>">

这将捕捉所有未被取消的事件(如果你愿意,你甚至可以获得这些事件,尽管我认为这不是一个好习惯)。

举个简单的例子,创建一个窗口并在其上放置一个按钮。在窗口中,为click操作添加一个处理程序(在ButtonBase上定义)

<Window ... ButtonBase.Click="Window_Click">

除非事件被故意取消,否则任何时候点击任何子按钮都会触发,甚至在子控件内部也是如此。