C# 难倒-冒泡一个路由事件到顶部窗口在WPF-如何捕捉任何地方!

C# 难倒-冒泡一个路由事件到顶部窗口在WPF-如何捕捉任何地方!,c#,wpf,C#,Wpf,这方面的文献非常糟糕——我只想从我定义的控件中冒泡出一个事件,但是从代理控制器类中动态创建(希望这不会引起问题)。控件是一个弹出窗口 public static readonly RoutedEvent weClosed = EventManager.RegisterRoutedEvent("TIMBOO", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FixedTaskbarNotifier)); // Pr

这方面的文献非常糟糕——我只想从我定义的控件中冒泡出一个事件,但是从代理控制器类中动态创建(希望这不会引起问题)。控件是一个弹出窗口

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 ..
                }
我希望能在某个地方捕捉到这一事件——即使是在我父母的窗口中,或者在视觉树的更高位置。这是对保存通知控件列表的控制器的引用-一旦我知道哪一个已关闭,我可以通过控制器重新组织/重新绘制任何其他仍处于活动状态的控件,但如何捕获?
谢谢

在您的父级上,或者在您想要处理它的任何地方,您应该能够通过声明声明事件的类和事件名称来处理该事件。在您的情况下,在窗口声明中,执行以下操作:

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

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

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



这将在单击任何子按钮时触发,即使是在子控件内部等,除非故意取消该事件。

我同意,MSDN上关于冒泡/隧道的文档一点也不好

我发现这篇MSDN杂志的文章更能解释这些冒泡事件

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

事件路由

了解一点 关于逻辑树和可视树是 重要,因为路由事件 主要基于可视 树。路由事件支持 气泡、隧道或管道的布线策略 直接的

泡沫是最常见和最常见的 意味着一个事件将冒泡 (传播)从中向上传播可视化树 源元素,直到 已处理或已到达根部 元素。这允许您处理 事件,该事件发生在更高级别的对象上 源中的元素层次结构 元素。例如,您可以附加 按钮。单击 封闭网格元素而不是 直接在按钮本身上。泡泡 事件只是有名称表示 他们的行为(例如,MouseDown)

隧道事件发生在另一个地方 方向,从根部开始 元素并沿 元素树,直到它们被处理或 到达目标的源元素 事件这允许上游元素 拦截事件并对其进行处理 在事件到达源之前 元素。隧道事件有其特殊性 前缀为Preview by的名称 约定(如PreviewMouseDown)

直接事件的行为与正常情况类似 NET Framework中的事件。唯一的 事件的潜在处理程序是 连接到 事件

通常,如果隧道事件 为特定事件定义,有 是一个相应的气泡事件。在里面 在这种情况下,隧道事件发生了 首先,从根开始,然后 一直到源头 元素查找处理程序。一旦 已处理或已到达 源元素,气泡事件为 被解雇了,一路从山上爬上去 源元素并查找 处理程序。泡泡或隧道事件确实如此 不能仅仅因为 调用事件处理程序。如果你愿意 停止冒泡或隧道 进程,则将事件标记为已处理 在事件处理程序中使用事件 传递给您的参数:

一旦处理程序将事件标记为 如果已处理,则不会将其提升到任何级别 更多的处理程序。嗯,那只是 部分正确。事实上,这件事 路由仍在幕后进行, 您可以显式地连接事件 重写为的代码中的处理程序 UIElement.AddHandler方法 有一个额外的标志来有效地 说:“即使活动已经结束,也给我打电话 已标记为已处理。”是否指定 那面旗上有一个像 以下:

AddHandler的第一个参数是 要处理的RoutedEvent。 第二个是对 事件处理方法(需要 要获得正确的签名 事件的委托)。第三个参数 指示您是否希望成为 即使另一个处理程序 将事件标记为已处理。这个 在其上调用AddHandler的元素 就是那个将要关注的人 路由过程中要经过的事件

希望这有帮助

<Window ... ButtonBase.Click="Window_Click">
private void OnChildElementMouseDown(object sender, MouseButtonEventArgs e) { e.Handled = true; }
m_SomeChildElement.AddHandler(UIElement.MouseDownEvent, (RoutedEventHandler)OnMouseDownCallMeAlways,true);