Beta 2 Event Bubbling

There are many great changes in Beta 2, and some are designed to make Silverlight more like WPF. One side effect of this is that event bubbling has changed just a bit and that bit breaks some of the examples I love to use.

In Beta 1, the distinction was that all the controls handled their own click events but the more primitive events such as many of the mouse events were allowed to bubble. This allowed for interesting if not terribly useful demonstrations in which I placed a check box inside a button and was able to demonstrate that if I were to use the click event on the check box the button would never see the click, but if I used a MouseLeftButtonDown, hey! Presto! the button did see the event.

This has now changed in Beta 2 to make Silverlight behave more like WPF. By and large (other than breaking my demo) this is a good thing.  The consistency now is that objects that directly derive from UI element do support event bubbling for the mouse events (that is,  Ellipse, Glyphs, Image, InkPresenter, Line, MediaElement, Path, Polygon, Polyline, Rectangle and TextBlock.)  In addition, the container classes do.

Thus, if you set up the following bizarre application in which you have a grid, with a grid in it, that contains a stack panel that in turn contains a rectangle, a TextBlock, a check box, a button and a listbox (the last to show the results)…

<UserControl x:Class="EventBubbling.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="800">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid x:Name="InterimGrid" >
            <StackPanel x:Name="myStackPanel" Orientation="Vertical"  >
                <Rectangle x:Name="myRect" Width="30" Height="30" Fill="Blue"
                    Stroke="Red" StrokeThickness="2" Margin="0,10,0,10" />
                <TextBlock x:Name="myTextBlock" Text="Hello"  
                    HorizontalAlignment="Center" FontSize="14" Margin="0,10,0,10"/>
                <CheckBox x:Name="myCheckBox" Content="Check Me" Width="80" 
                    Height="40" Margin="0,10,0,10" HorizontalAlignment="Center" />
                <Button x:Name="myButton" Content="TinyButton" Height="30" 
                    Width="70" Margin="0,10,0,10" FontSize="12" HorizontalAlignment="Center" />
                <ListBox x:Name="Messages" Width="150" Height="400" />      
        </StackPanel>
      </Grid>
    </Grid>
</UserControl>

and you add MouseLeftButtonDown event handlers for everything (except the list box):

void Page_Loaded(object sender, RoutedEventArgs e)
{
    LayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(
        LayoutRoot_MouseLeftButtonDown);
    InterimGrid.MouseLeftButtonDown += new MouseButtonEventHandler(
        InterimGrid_MouseLeftButtonDown);
    myStackPanel.MouseLeftButtonDown += new MouseButtonEventHandler(
        myStackPanel_MouseLeftButtonDown);
    myRect.MouseLeftButtonDown += new MouseButtonEventHandler(
        myRect_MouseLeftButtonDown);
    myTextBlock.MouseLeftButtonDown += new MouseButtonEventHandler(
        myTextBlock_MouseLeftButtonDown);
    myCheckBox.MouseLeftButtonDown += new MouseButtonEventHandler(
        myCheckBox_MouseLeftButtonDown);
    myButton.MouseLeftButtonDown += new MouseButtonEventHandler(
        myButton_MouseLeftButtonDown);
}

 

 

 

where all the handlers do the same thing, they add to the list box (there are more efficient ways to write this!)

void InterimGrid_MouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
{
    Messages.Items.Add(" InterimGrid ");
}

What you find is that when you click on the rectangle or the text block the event bubbles all the way to the top most grid, but if you click on the checkbox or the button the event is “handled” by that control and is not bubbled at all.

BubblingNoMore

In the image, I’ve clicked on the rectangle and the event was registered by the rectangle, the StackPanel that encloses it, the Grid that holds the StackPanel and the outermost grid.  I’m now clicking on the button, and while the button is registering the mouse down, it is not passing it along to anyone else.

One fascinating aspect of this (at least to me, but I don’t get out much) is that if I inject a button into the middle of the stream, by putting the rectangle, textblock checkbox and button inside an outer button…

<UserControl x:Class="EventBubbling.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="600">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid x:Name="InterimGrid" >
            <Grid.RowDefinitions>
                <RowDefinition Height="120" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Button x:Name="OuterButton" Width="300" Height="100" Grid.Row="0">
                <StackPanel x:Name="myStackPanel" Orientation="Horizontal"  >
                    <Rectangle x:Name="myRect" Width="50" Height="30" Fill="Blue"
                        Stroke="Red" StrokeThickness="2" Margin="5,0,5,0" />
                    <TextBlock x:Name="myTextBlock" Text="Hello"  
                        VerticalAlignment="Center" FontSize="14" Margin="5,0,5,0"/>
                    <CheckBox x:Name="myCheckBox" Content="Check Me" Width="80" 
                        Height="40" Margin="5,0,5,0" VerticalAlignment="Center" />
                    <Button x:Name="myButton" Content="TinyButton" Height="30" 
                        Width="70" Margin="5,0,5,0" FontSize="12" VerticalAlignment="Center" />
                </StackPanel>
            </Button>
            <ListBox x:Name="Messages" Width="150" Height="400" Grid.Row="1"/>      
        </Grid>
    </Grid>
</UserControl>

The key changes are that I’ve created two rows (one for the controls, one for the list box) and injected a button above the stack panel that holds the stack panel and all its contents (now horizontal). Let’s run the same experiment…

BubblingNoMore2

Once again, I clicked on the Rectangle, and then was clicking on the button when I took the image. Once again the button had no bubbling, but notice that the Rectangle did not bubble as far as it had previously. After it hit the stack panel it hit the outer button which ate the MouseLeftButtonDown event, and did not pass it along to any containers above it.

All of this is as it should be, and will end a lot of confusion for folks coming over from WPF, but if you learned about bubbling from me, then you’ll want to know about this change.

(Source code posted when Beta2 Ships)

Thanks

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses. He was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP.
This entry was posted in z Silverlight Archives. Bookmark the permalink.

One Response to Beta 2 Event Bubbling

  1. john says:

    Thanks for the post.

    Any changes regarding the above in sl 3 or 4?

Comments are closed.