14

I understand how bubbling and tunneling works. However, i'm confused about using them. Here is why:

I want to handle a mouse click event. To bubble it, there is MouseDown and, to tunnel it, there is PreviewMouseDown. However, MouseDown doesn't necessarily mean the user clicked the control. May be the user pressed the button and moved away from it to cancel the click. I wouldn't want to change anything if the button is not being clicked.

So my question is, how are the Bubbling/Tunneling strategies useful?

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
SanSolo
  • 2,267
  • 2
  • 24
  • 32

3 Answers3

9

If the event is listed RoutedEventArgs, then it's routed event. Routed events support a RoutingStrategy of Bubble, Tunnel, or Direct. Let's take a look at the event handler of Button.Click:

private void Grid_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Button Test clicked!");
}

There specified RoutedEventArgs, so it's routed event. Because the preview were not specified in the name, therefore this Bubble event. This can be demonstrated in the following way:

<Grid ButtonBase.Click="Grid_Click">
    <Button Name="TestButton" Width="100" Height="30" Content="Test" />
</Grid>

When you click on the TestButton, the event is to rise above the Grid, and displays a message:

Button Test clicked!

Usefulness of Bubbling/Tunneling strategies

Tunneling

Many of the standard controls listen to events, such as KeyDown, MouseDown, etc. For example -DataGrid control. I want by pressing the enter key the function was called adding a record. But DataGrid already has KeyDown event, so the event is not raised. So you have to do your logic in the Tunnel event - PreviewKeyDown, it will work before the KeyDown event. The same applies to RichTextBoxControl.

Bubbling

Sometimes, you need a global handler for a specific event, so it worked for all controls in VisualTree. Naturally, the a direct event you can not do it. Hence on the stage comes Bubbling event.

Another reason is the ideology of the WPF. This Button can contain anything: Image, another Button, etc:

enter image description here

The user can click on the TextBlock/Image in the Button. How do we know that the click was in Button? That's right, with the help of Bubbling event.

For more information, please see:

Understanding Routed Events and Commands In WPF

Edit

I changed little bit a Click handler:

private void Grid_Click(object sender, RoutedEventArgs e)
{
    String message = "#" + eventCounter.ToString() + ":\r\n" +
            " Sender: " + sender.ToString() + ":\r\n" +
            " Source: " + e.Source + ":\r\n" +
            " Original Source: " + e.OriginalSource;

    lstEvents.Items.Add(message);
}

Result of click on the Button:

enter image description here

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
  • But, as far as i know, Click is a direct event rather than Bubbling event. – SanSolo Sep 04 '13 at 05:19
  • 1
    @SanSolo: If it was direct, then message `Button Test clicked!` did not appear. We set a handler for the `Grid`, not to the `Button`, and a click on the `Button`, the event worked for the `Grid`. The event at the `Button` moved up, and came to the `Grid`. Direct click event, as far as I know, has been in *`WinForms`*. – Anatoliy Nikolaev Sep 04 '13 at 05:40
  • 1
    Yes, you are right. I ran the example you provided to check Sender,Source and original Source. Thw values were Grid, Button and Button:Test respectively. So by default, all WPF events are bubbling events? This is confusing...tunneling events have preview keyword, but don't know which are bubbling events. – SanSolo Sep 04 '13 at 05:52
  • 1
    @SanSolo: By default, all events are `RoutedEvents`. True, if the name is in *`preview`*, it Tunnel event. You can view the article I gave you in my answer. – Anatoliy Nikolaev Sep 04 '13 at 05:56
  • 1
    Thanks. I found this on [another msdn article](http://msdn.microsoft.com/en-us/library/ms742806.aspx): >he event route can travel in one of two directions depending on the event definition, but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window). So, default strategy is bubbling. – SanSolo Sep 04 '13 at 06:13
4

Hi though you can get some good articles regading this on net but still I will try to answer this.

Suppose you give a button a very plain appearance consisting of a single Rectangle, and provide a simple piece of text as the content Even with such basic visuals, there are still two elements present: the text and the rectangle.The button should respond to a mouse click whether the mouse is over the text or the rectangle. In the standard .NET event handling model, this would mean registering a MouseLeftButtonUp event handler for both elements.

This problem would get much worse when taking advantage of WPF’s content model. A Button is not restricted to having plain text as a caption—it can contain any object as content. The xaml below is not especially ambitious, but even this has six visible elements: the yellow outlined circle, the two dots for the eyes, the curve for the mouth, the text, and the button background itself. Attaching event handlers for every single element would be tedious and inefficient. To work MouseDown We would have to add 8 MouseDownEvents to this bit of code.

<Button PreviewMouseDown="PreviewMouseDownButton" MouseDown="MouseDownButton">
        <Grid PreviewMouseDown="PreviewMouseDownGrid" MouseDown="MouseDownGrid">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Canvas PreviewMouseDown="PreviewMouseDownCanvas" MouseDown="MouseDownCanvas" Width="20" Height="18" VerticalAlignment="Center">
                <Ellipse PreviewMouseDown="PreviewMouseDownEllipse" MouseDown="MouseDownEllipse" x:Name="myEllipse" Canvas.Left="1" Canvas.Top="1" Width="16" Height="16" Fill="Yellow" Stroke="Black" />
                <Ellipse Canvas.Left="4.5" Canvas.Top="5" Width="2.5" MouseDown="MouseDownEllipse" Height="3" Fill="Black" />
                <Ellipse Canvas.Left="11" Canvas.Top="5" Width="2.5" MouseDown="MouseDownEllipse" Height="3" Fill="Black" />
                <Path Data="M 5,10 A 3,3 0 0 0 13,10" Stroke="Black" MouseDown="Path_MouseDown_1"/>
            </Canvas>
            <TextBlock Grid.Column="1" MouseDown="TextBlock_MouseDown_1">Click!</TextBlock>
        </Grid>
    </Button>

WPF uses RoutedEvents Bubble/Tunnel /Normal, which are rather more thorough than normal events. Instead of just calling handlers attached to the element that raised the event, WPF walks the tree of user interface elements, calling all handlers for the routed event attached to any node from the originating element right up to the root of the user interface tree.

yo chauhan
  • 12,079
  • 4
  • 39
  • 58
  • That answer clarifies the need for Bubbling/Tunneling, which is the title of my question. However, i'm still confused about why we would use MouseUp or MouseDown given that it is a not a conclusive action like Click. MousewheelUp/Down i can see scenarios where it is useful.But in case of MouseUp, we change something, user moves away from the button, there is no click...where would we use it? – SanSolo Sep 04 '13 at 05:13
1

As you said you know the concept of bubbling/tunneling so not going into that. But this is what these events are intended for i.e they let you know if the Mouse button was Down or Up on the control or its children.Events are working fine.For your scenario you should use the Click event of your button which tell if the mouse was down and up on the button itself.

Thanks

Nitin
  • 18,344
  • 2
  • 36
  • 53