Em1
Em1

Reputation: 1095

Why does the Handled property in PreviewMouseLeftButtonDownEvent affect a ClickEvent?

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.

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);
}

Upvotes: 1

Views: 4581

Answers (1)

Sheridan
Sheridan

Reputation: 69959

I've never thought that event handlers of different types could affect each other

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:

For instance, a Windows Presentation Foundation (WPF) Button suppresses MouseLeftButtonDown and MouseLeftButtonDown bubbling events raised by the Button or its composite elements in favor of capturing the mouse and raising a Click event that is always raised by the Button itself. The event and its data still continue along the route, but because the Button marks the event data as Handled, only handlers for the event that specifically indicated they should act in the handledEventsToo case are invoked.

Furthermore, you said this:

When I add e.Handled = true to the Mouse...-EventHandler, all three event handlers are invoked

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:

For input events specifically, Preview events also share event data instances with the equivalent bubbling event. If you use a Preview event class handler to mark the input event handled, the bubbling input event class handler will not be invoked. Or, if you use a Preview event instance handler to mark the event handled, handlers for the bubbling event will not typically be invoked.

Upvotes: 2

Related Questions