Search code examples
c#wpfevent-handlingrouted-events

Is this the way RoutedEventArgs.Handled works?


On my way to understanding WPF RoutedEvent handling, is this the way it works?
Say I have a Window with a Grid and a Button inside the Grid. My Button_Click event handler looks like this:

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

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

This is where I'm beginning to get lost.

  • 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?
  • Is there a point where the bubbling stops by itself?
  • 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?

Solution

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

    No, it does not. It only indicates to subsequent event handlers on the route up the element tree that another event handler before has marked the event as handled.

    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?

    Yes, but it depends. In some cases, controls will mark an event automatically as handeled, e.g. Button, so in these cases event if other elements had handlers for such an event attached, they would not have been executed.

    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.

    Moreover, in XAML, if you add an event handler, it will only be executed if the event is not handled, yet. However, in code-behind, you can still add an event handler that is executed even if e.Handled is true using the AddHandler method on UIElements and passing true to the handledEventsToo argument.

    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.

    As said before, this is only possible in code-behind, there is no XAML syntax for it.

    Is there a point where the bubbling stops by itself?

    Yes, it stops at the root of the element tree, in the majority of cases e.g. a Window.

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

    The event will still be propagated, that is how the routed event mechanism works. Of course, if other handlers are not invoked because the event is marked as handled, those lines are not executed, but that changes the functionality of your application, which is a different story. As a general rule, do not optimze prematurely. If there is a preformance issue anytime, then use a profiler to analyze your application, get reliable and meanigful data to find the hotspots and solve the issue there. There is no need or benefit in optimizing something beforehand that will not likely be a performance concern.

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

    Again it depends on what you want to achieve. Suppose you have a ListView with lots of items. It shows a scrollbar that can be operated using the mouse wheel. So when you start to scroll the mouse wheel, an event is raised that invokes scrolling the embedded ScrollViewer. In this case, the event is handled automatically. Why? If this ListView was part of a large UI Control with other parent ScrollViewers they would scroll, too, if the event was not handled. Imagine multiple nested controls scrolling all at once, that would be terrible. In other scenarios there may be a need that parent controls also get the event.

    This is an excerpt from the documentation on 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.

    The full paragraph gives you a more detailed idea of what a significant and complete way is, but as you can see, there is no golden rule that you can apply, it dependes on your requirements and design.