Consider you add a ClickEvent- and PreviewMouseLeftButtonDown-Handler for a Button
<Button x:Name="button"
Click="Button_Click"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
</Button>
When clicking the Button, first PreviewMouseLeftButtonDown is fired, then the Click-Event.
If you set e.Handled = true
in the Preview...-Event, the Click-Event is not handled any more.
However, now let's think of the MouseLeftButtonDownEvent.
First, this event's routing strategy is direct. That is, it is re-raised for every control. In contrast, the Preview...-Event is tunneling, the Click-Event is bubbling.
Second, adding a MouseLeftButtonDownEventHandler is only successful when registering the handler such that it is even invoked for already handled events, as shown in the following code excerpt.
button.AddHandler(MouseLeftButtonDownEvent,
new MouseButtonEventHandler(Button_MouseLeftButtonDown),
true);
I've written a test application, having a button, and added a handler for each of the Events. When an event handler is invoked, it writes some information into a text block.
- When I click the button, all three event handlers are invoked.
- When I add
e.Handled = true
to the Preview...-EventHandler, only this event handler is invoked. Even the Mouse...-EventHandler is not raised, although I've setUIElement.AddHandler handledEventsToo
to true. - When I add
e.Handled = true
to the Mouse...-EventHandler, all three event handlers are invoked.
That does not make any sense to me. Mouse...-EventHandlers do not affect the Click-EventHandlers, but Preview...-EventHandlers affect both Mouse...- and Click-EventHandlers.
And even 'forcing' to handle an event failed for the Mouse...-EventHandler.
Actually, I've never thought that event handlers of different types could affect each others. What I understood is that if I've got a Preview...-Event and a Click-Event, that these are independent.
So, what am I missing?
Here's the pretty simple sample code:
XAML:
<DockPanel>
<Border x:Name="border" DockPanel.Dock="Top" Height="50"
BorderBrush="Gray" BorderThickness="1">
<StackPanel x:Name="stackpanel" Background="LightGray"
Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="button" Width="Auto"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
Click Me
</Button>
</StackPanel>
</Border>
<Border DockPanel.Dock="Bottom" BorderBrush="Gray" BorderThickness="1">
<ScrollViewer>
<TextBlock x:Name="textBlock" TextWrapping="Wrap"/>
</ScrollViewer>
</Border>
</DockPanel>
Code-Behind:
public MainWindow()
{
InitializeComponent();
button.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(Button_MouseLeftButtonDown), true);
button.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true);
stackpanel.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true /*false*/ );
}
private void Output(object sender, RoutedEventArgs e)
{
textBlock.Text += "RoutedEvent: " + e.RoutedEvent + "\n";
textBlock.Text += "Sender: " + sender + "\n";
textBlock.Text += "Source: " + e.Source + "\n";
textBlock.Text += "OriginalSource: " + e.OriginalSource + "\n" + "\n";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// e.Handled = true;
Output(sender, e);
}
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// e.Handled = true;
Output(sender, e);
}
private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Output(sender, e);
}
You are mostly correct, as this is quite rare, but you can find your answers in the Preview Events page on MSDN. From the linked page:
Furthermore, you said this:
That is expected, as setting
e.Handled
in a bubbling event handler will do nothing... there is nothing that will read that value after the event has left the handler code.e.Handled
is predominantly used in tunnelling event handlers to stop the events from any further routing. Again, from the linked page: