这是 RoutedEventArgs.Handled 的工作方式吗?

Is this the way RoutedEventArgs.Handled works?

在了解 WPF RoutedEvent 处理的过程中,这是它的工作方式吗?
假设我有一个 Window,在 Grid 中有一个 Grid 和一个 Button。我的 Button_Click 事件处理程序如下所示:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Do stuff
    e.Handled = true;
}

调用 e.Handled = true; 停止事件在可视化树中冒泡。

这是我开始迷路的地方。

Calling e.Handled = True; stops the event bubbling up the visual tree.

不,it does not。它仅向元素树上的后续事件处理程序指示之前的另一个事件处理程序已将事件标记为已处理。

If I understand correctly, not calling e.Handled = True; could result in another event handler firing in the Grid or the Window if they had an event listener for Click active?

是的,但这要视情况而定。在某些情况下,控件将 mark an event automatically as handeled, e.g. Button,因此在这些情况下,如果其他元素附加了此类事件的处理程序,它们将不会被执行。

The ButtonBase marks the MouseLeftButtonDown event as handled in the OnMouseLeftButtonDown method and raises the Click event. Hence, the OnMouseLeftButtonDown event will never occur for a control that inherits from ButtonBase.

此外,在XAML中,如果添加事件处理程序,只有在未处理事件时才会执行。但是,在 code-behind 中,您仍然可以添加一个事件处理程序,即使 e.Handledtrue 使用 AddHandler method on UIElement 并将 true 传递给 handledEventsToo 参数。

public void AddHandler (System.Windows.RoutedEvent routedEvent, Delegate handler, bool handledEventsToo);

Adds a routed event handler for a specified routed event, adding the handler to the handler collection on the current element. Specify handledEventsToo as true to have the provided handler be invoked for routed event that had already been marked as handled by another element along the event route.

如前所述,这仅在 code-behind 中可用,没有 XAML 语法。

Is there a point where the bubbling stops by itself?

是的,在大多数情况下,它会停在 root of the element tree,例如Window.

Is there a performance effect if I don't stop the event propagation?

事件仍将被传播,这就是路由事件机制的工作原理。当然,如果由于事件被标记为已处理而未调用其他处理程序,则不会执行这些行,但这会改变应用程序的功能,这是另一回事。作为一般规则,不要过早优化。如果任何时候出现性能问题,那么 使用分析器 来分析您的应用程序,获取可靠且有意义的数据以找到热点并解决那里的问题。预先优化不太可能成为性能问题的东西没有必要也没有好处。

And the most important, should I, by default, mark the event handled?

同样,这取决于您想要实现的目标。假设您有一个包含很多项目的 ListView。它显示了一个可以使用鼠标滚轮操作的滚动条。因此,当您开始滚动鼠标滚轮时,会引发一个事件来调用滚动嵌入的 ScrollViewer。在这种情况下,事件会自动处理。为什么?如果这个 ListView 是一个大型 UI 控件的一部分,而其他父控件 ScrollViewer 则它们也会滚动,如果事件没有被处理的话。想象一下多个嵌套控件同时滚动,那会很糟糕。在其他情况下,可能需要父控件也获取事件。

这是 When to Mark Events as Handled 上文档的摘录:

There is no absolute rule for when you should mark routed events as handled, either as an application author, or as a control author who responds to existing routed events or implements new routed events. For the most part, the concept of "handled" as carried in the routed event's event data should be used as a limited protocol for your own application's responses to the various routed events exposed in WPF APIs as well as for any custom routed events. Another way to consider the "handled" issue is that you should generally mark a routed event handled if your code responded to the routed event in a significant and relatively complete way.

完整的段落让您更详细地了解什么是 重要完整 方式,但是如您所见,没有可以应用的黄金法则,这取决于您的要求和设计。