Why doesn't button click event "bubble up visual tree" to StackPanel as MSDN article states?


Question

In the MSDN article Understanding Routed Events and Commands In WPF, it states

an event will bubble (propagate) up the visual tree from the source element until either it has been handled or it reaches the root element.

However, in this example, when you click the button, it doesn't "bubble up the visual tree" to get handled by the parent StackPanel event, i.e. clicking on the button fires no event.

Why not? What do they mean then by "bubbling up" if not this?

XAML:

<Window x:Class="TestClickEvents456.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel x:Name="TheStackPanel"
                Background="Yellow"
                MouseDown="TheStackPanel_MouseDown">
        <Button x:Name="TheButton"
                Margin="10"
                Content="Click This"/>
        <TextBlock x:Name="TheMessage"
                   Text="Click the button or the yellow area"/>
    </StackPanel>
</Window>

code-behind:

using System.Windows;
using System.Windows.Input;

namespace TestClickEvents456
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void TheStackPanel_MouseDown(object sender, MouseButtonEventArgs e)
        {
            TheMessage.Text = "StackPanel was clicked.";
        }

    }
}
1
21
1/11/2019 6:34:34 AM

Accepted Answer

The event bubbles up, until it gets handled...

Since the Button does something with your mouse clicks, it absorbs your mouse event and turns it into a ClickEvent.

If you use the PreviewMouseDown, you see that the StackPanel first receives the event before the button does.. Preview events use the Tunnel down approach..

25
3/16/2016 8:47:03 AM

As others have said, it's because the MouseDown event gets handled by the Button before it can be bubbled further. You can see this in Reflector, in ButtonBase.OnMouseLeftButtonDown:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
    if (this.ClickMode != ClickMode.Hover)
    {
        e.Handled = true;
        // SNIP...
    }
    base.OnMouseLeftButtonDown(e);
}

One solution is to listen for a MouseDown event, and indicate that you don't care if the event is handled. You can do this with the AddHandler method. It has a boolean overload that lets you listen for events which are already handled.

If you do this somewhere instead of setting the MouseDown handler in XAML:

TheStackPanel.AddHandler(MouseDownEvent, new MouseButtonEventHandler(TheStackPanel_MouseDown), true);

You'll receive all MouseDown events on TheStackPanel, regardless of whether they've been handled.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon