views:

282

answers:

2
+2  Q: 

Button.MouseDown

Hi Guys,

I'm relatively new with WPF. I'm trying to understand the difference between MouseDownEvent and PreviewMouseDownEvent.

I understand the WPF event strategies and i understand that the MouseDown event is a bubbling event and the PreviewMouseDown is a tunneling event.

I also understand the order of which these events are being fired - according to this MSDN overview http://msdn.microsoft.com/en-us/library/ms742806.aspx#routing (there is a diagram with example there).

So i tried to code some my self, check this for example:

<Grid x:Name="grid" Width="250">
    <StackPanel Mouse.MouseDown="StackPanel_MouseDown" PreviewMouseDown="StackPanel_PreviewMouseDown">
    <WPFVisualizerExample:MyButton x:Name="B1" PreviewMouseDown="B1_PreviewMouseDown" MouseDown="B1_MouseDown" Margin="5,5,5,5">
            <WPFVisualizerExample:MyButton x:Name="B2" PreviewMouseDown="B2_PreviewMouseDown" MouseDown="B2_MouseDown"  Margin="5,5,5,5">
                <WPFVisualizerExample:MyButton x:Name="B3" PreviewMouseDown="B3_PreviewMouseDown" MouseDown="B3_MouseDown"  Margin="5,5,5,5">Click Me</WPFVisualizerExample:MyButton>
            </WPFVisualizerExample:MyButton>
    </WPFVisualizerExample:MyButton>           
    </StackPanel>        
</Grid>

I have an event handler for each of the events (the preview and non-preview) and i wanted to see what is happening, which of the event is being thrown (i have a message box shown for each event).

The 'MyButton' user control simply extends the base Button and override the OnMouseDown and OnPreviewMouseDown to set the e.Handled false:

    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnMouseDown(e);
        e.Handled = false;
    }

    protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnPreviewMouseDown(e);
        e.Handled = false;
    }

(tried with this and without this).

According to the MSDN overview (in the link above), if i have 3 elements then the events route should be as follows:

PreviewMouseDown (tunnel) on root element.

PreviewMouseDown (tunnel) on intermediate element #1.

PreviewMouseDown (tunnel) on source element #2.

MouseDown (bubble) on source element #2.

MouseDown (bubble) on intermediate element #1.

MouseDown (bubble) on root element.

So I expected the the message boxes to be shown according to the above. From some reason - which I don't understand only the preview events are being thrown (according to what the MSDN says Preview_B1=>Preview_B2=>Preview_B3). My expectations were: Preview_B1=>Preview_B2=>Preview_B3=>NonPreview_B3=>NonPreview_B2=>NonPreview_B1.

But the non-preview events are not being thrown at all.

So basically I don't understand the route of the events, from MSDN overview I understood that the route starts from the root element, goes down (tunnel) to the source element and then back up (bubble) to the root element, but this is not what happening in practice.

It is really important for me to understand how this events are working, i probably miss-understand something basic here, your help will be appreciated.

THANX!! -Gili

+2  A: 

Since the function of the Button control is to produce a Click event (or fire a Command) it treats the Mouse events a little differently than other controls. When Button receives a PreviewMouseDown event it converts it to a Click event, cancelling any further tunnelling of Preview and the MouseDown bubbling event. There is some variation in this depending on the ClickMode setting of the Button. If you'd rather use the Mouse events themselves you can just use a ContentControl instead (try it and you should see exactly what you expected) but you'll probably find it's much easier to use Button.Click in most cases.

UPDATE

There must be something else going on in your code that's causing the event routing to stop. Here's an example similar to yours that I verified that shows expected output (some styling added to make the elements obvious):

<Window.Resources>
    <Style TargetType="{x:Type ContentControl}">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="Background" Value="PaleGreen" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<StackPanel Tag="Panel" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
    <ContentControl BorderBrush="Red" Tag="C1" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
        <ContentControl BorderBrush="Green" Tag="C2" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
            <ContentControl Content="Click Me" BorderBrush="Blue" Tag="C3" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown"/>
        </ContentControl>
    </ContentControl>
</StackPanel>

and simple handlers to write to Debug:

private void PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Preview");
}

private void MouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Bubble");
}

Debug Output (if center text is clicked) is:

Panel Preview
C1 Preview
C2 Preview
C3 Preview
C3 Bubble
C2 Bubble
C1 Bubble
Panel Bubble

John Bowen
Please see my answer above, i have changed the Button to ContentControl and i still get the same result. (I just want to understand how RoutedEvents work in WPF, the documentation seem to say one thing and in practice different things happen). THANX ALOT!!!
Gilad
A: 

Hi,

I took your advice and replaced the Buttons with ContentControls as follows:

<Grid x:Name="grid" Width="250">
    <StackPanel Mouse.MouseDown="StackPanel_MouseDown" PreviewMouseDown="StackPanel_PreviewMouseDown">
    <ContentControl x:Name="B1" PreviewMouseDown="CC1_PreviewMouseDown" MouseDown="CC1_MouseDown" Margin="5,5,5,5">
            <ContentControl x:Name="B2" PreviewMouseDown="CC2_PreviewMouseDown" MouseDown="CC2_MouseDown"  Margin="5,5,5,5">
                <ContentControl x:Name="B3" PreviewMouseDown="CC3_PreviewMouseDown" MouseDown="CC3_MouseDown"  Margin="5,5,5,5">Click Me</ContentControl>
            </ContentControl>
        </ContentControl>           
    </StackPanel>        
</Grid>

What I get is the following:

Preview_CC1=>Preview_CC2=>Preview_CC3

What I expect to get is:

Preview_CC1=>Preview_CC2=>Preview_CC3=>Non_Preview_CC3=>Non_Preview_CC2=>Non_Preview_CC1

Am i missing something?

Thanx! Gili

Gilad