WPF Event Bubbling and Routed Events

Consider a User Control with a single button on it:

  1. <UserControl x:Class="Tff.ButtonClickBubble.MainUserControl"
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
  5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
  6.              mc:Ignorable="d" Height="100" Width="100">
  7.     <Grid Background="Red" Margin="0,0,0,0">
  8.         <Button x:Name="MainButton"
  9.             Content="Push Me" HorizontalAlignment="Left"
  10.                 Margin="19,36,0,0" VerticalAlignment="Top"
  11.                 Width="62" Height="25"
  12.                 Click="MainButton_Click"/>
  13.     </Grid>
  14. </UserControl>

 

In the code behind, the click event shows a dialog

  1. public partial class MainUserControl : UserControl
  2. {
  3.     public MainUserControl()
  4.     {
  5.         InitializeComponent();
  6.     }
  7.  
  8.     private void MainButton_Click(object sender, RoutedEventArgs e)
  9.     {
  10.         MessageBox.Show(e.Source.ToString());
  11.     }
  12. }

After hitting F6 so the control will show in my toolbox, I then put an instance of that control on a basic page like so:

  1. <Window
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:local="clr-namespace:Tff.ButtonClickBubble" x:Class="Tff.ButtonClickBubble.MainWindow"
  5.         Title="MainWindow" Height="236" Width="184">
  6.     <Grid x:Name="MainGrid" Background="AliceBlue">
  7.         <local:MainUserControl HorizontalAlignment="Left" Margin="35,44,0,0" VerticalAlignment="Top"/>
  8.     </Grid>
  9. </Window>

 

When I hit F5, I get the expected MessageBox:

image

So now I want the main window to intercept that button click and pop its own dialog box.  The Window class does not have a click event – rather it has a mousedown event.  By adding the mouse down event hander to the main window, I have this:

  1. <Window
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:local="clr-namespace:Tff.ButtonClickBubble" x:Class="Tff.ButtonClickBubble.MainWindow"
  5.         Title="MainWindow" Height="236" Width="184" MouseDown="Window_MouseDown">

 

And in the code behind:

  1. private void Window_MouseDown(object sender, MouseButtonEventArgs e)
  2. {
  3.     MessageBox.Show(e.Source.ToString());
  4. }

 

Unfortunately, that doesn’t work.  The button click event swallows the event so the MouseDown only fires on the part of the window where the button is not:

imageimage

So I went into StackOverflow and I found this post that I think describes the problem.  So I changed the MouseDown to the PreviewMouseDown event and sure enough, I can handle the event from the main screen:

image

But the ClickEvent on the button is not being fired.  I then added a e.handled = false but that did not help:

  1. private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
  2. {
  3.     MessageBox.Show(e.Source.ToString());
  4.     e.Handled = false;
  5. }

 

So the answer marked as correct on stack overflow does apply here.  The answer below the marked as correct answer is relevant.  I tried to add a handler to the Grid (Windows don’t have AddHandler methods) like this:

  1. public MainWindow()
  2. {
  3.     InitializeComponent();
  4.     MainGrid.AddHandler(MouseDownEvent, new MouseButtonEventHandler(MainGrid_MouseDown), true);
  5. }
  6.  
  7. private void MainGrid_MouseDown(object sender, MouseButtonEventArgs e)
  8. {
  9.     MessageBox.Show(e.Source.ToString());
  10. }

 

The problem is that it is not working either.  Fortunately, the answer below THAT one does work:

  1. <Window
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:local="clr-namespace:Tff.ButtonClickBubble" x:Class="Tff.ButtonClickBubble.MainWindow"
  5.         Title="MainWindow" Height="236" Width="184" >
  6.     <Grid x:Name="MainGrid" Background="AliceBlue" Button.Click="MainGrid_MouseDown">
  7.         <local:MainUserControl HorizontalAlignment="Left" Margin="35,44,0,0" VerticalAlignment="Top"/>
  8.     </Grid>
  9. </Window>

 

And

  1. public partial class MainWindow : Window
  2. {
  3.     public MainWindow()
  4.     {
  5.         InitializeComponent();
  6.     }
  7.  
  8.     private void MainGrid_MouseDown(object sender, RoutedEventArgs e)
  9.     {
  10.         MessageBox.Show(e.Source.ToString());
  11.     }
  12.  
  13. }

 

They key thing is wiring up the Grid like this:  Button.Click="MainGrid_MouseDown"

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: