Page view counter

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

Published 03 June 2008 03:57 PM by jesseliberty

Comments

# johnnystock said on 03 June, 2008 04:03 PM

That does make more sense to me now.  

I eagerly await more Beta 2 information as well (as well as a keyboard that corrects my spelling on the fly, that one may have to wait longer though)

:)

# chris_vickerson said on 03 June, 2008 08:09 PM

can we *see* the list of new features too? :D

# Page Brooks said on 03 June, 2008 10:06 PM

Silverlight 2 - Beta 2 arrives this week!

# jesseliberty said on 04 June, 2008 08:39 AM

>> can we *see* the list of new features too <<

The minute I have a comprehensive list, I will publish it or a link to it.

# Dew Drop – June 4, 2008 | Alvin Ashcraft's Morning Dew said on 04 June, 2008 08:39 AM

Pingback from  Dew Drop &ndash; June 4, 2008 | Alvin Ashcraft's Morning Dew

# kamii47 said on 04 June, 2008 01:12 PM

Is there any news about Expression blend 2.5 new beta

# Beta 2 Event Bubbling said on 05 June, 2008 10:26 PM

Pingback from  Beta 2 Event Bubbling

# Lyynx said on 10 June, 2008 03:23 AM

When I wire up a MouseLeftButtonDown event to a slider control the event is not raised when I click the button. Is this because the container it is in is handling the event?

My code no longer works;

           theSlider.MouseLeftButtonDown += new MouseButtonEventHandler(theSlider_MouseLeftButtonDown);

           theSlider.MouseEnter += new MouseEventHandler(theSlider_MouseEnter);

           theSlider.ValueChanged +=new RoutedPropertyChangedEventHandler<double>(theSlider_ValueChanged);

Will test the theory that something else is handling the event first.

thanks

Stephen

# Brauliod said on 13 June, 2008 03:51 AM

Jesse,

 Mmmm... I used the OnLButtonDown in the root canvas to perform drag and drop operations, now this doesn't work.

 As workarounds I have tought:

 - Convert all my textblocks to textboxes and subscribe to the Left Button Down event, but.. can I easily or manually resend the message to the root canvas?

 - A nasty trick is to place a transparent area, ... like we have done with the nasty HTML DIV's... but I think there must be a cleaner solution.

 Thanks,

   Braulio

# Flyte said on 26 June, 2008 07:03 PM

I've spent all day trawling Google, MSDN and Silverlight.net for an answer to firing MouseLeftButtonDown/Up events for a Slider, but thus far none of the solutions have worked.

I've tried putting grids / canvasses behind the slider, but it just doesn't fire when I use the slider. If I put a rectangle over the slider and make it invisible, I can't use the slider but the events do fire!

Please Jesse, could you fix it for me?!

Thanks,

Ellis

# Quick note: New TechEd downloads | Tamir Khason - Just code said on 01 January, 2009 03:50 AM

Pingback from  Quick note: New TechEd downloads | Tamir Khason - Just code

# Just Code - Tamir Khason said on 01 January, 2009 02:00 PM

[This blog was migrated. You will not be able to comment here. The new URL of this post is http://khason