views:

361

answers:

4

XAML

<TreeView Name="GroupView" ItemsSource="{Binding Documents}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <EventSetter Event="MouseDoubleClick" Handler="OnTreeNodeDoubleClick"/>
                </Style>
            </TreeView.ItemContainerStyle>
            ....
</TreeView>

Code-Behind

private void OnTreeNodeDoubleClick(object sender, MouseButtonEventArgs mouseEvtArgs)
       {
           Console.WriteLine("{3} MouseDoubleClick Clicks={0} ChangedButton={1} Source={2} Handled={4} ButtonState={5}",
               mouseEvtArgs.ClickCount, mouseEvtArgs.ChangedButton, mouseEvtArgs.OriginalSource,
               mouseEvtArgs.Timestamp, mouseEvtArgs.Handled, mouseEvtArgs.ButtonState);
       }

I find that for one double click, the event handler is called multiple times. I'm trying to open up a document in tab on a double-click on the corresponding tree node; so I'd need to filter out the extra calls.

23479156 MouseDoubleClick Clicks=1 ChangedButton=Left Source=System.Windows.Controls.TextBlock Handled=False ButtonState=Pressed
23479156 MouseDoubleClick Clicks=1 ChangedButton=Left Source=System.Windows.Controls.TextBlock Handled=False ButtonState=Pressed

In my slightly-complicated app, it is being raised 4 times per double-click. On a simple repro-app, it is being raised 2 times per double click. Also all the event argument parameters are the same too, so I can't distinguish the last one of a set.

Any ideas why this is the way it is?

A: 

The most likely reason is that the doubleclick handler is installed multiple times, so each instance of the handler is being called once for each click.

John Knoeller
@John - did a find in all files, the only place where OnTreeNodeDoubleClick in mentioned is in the Style definition
Gishu
A: 

This is the wonderful world of event bubbling. The event is bubbling up the node hierarchy of your TreeView and your handler is called once for every node in the hierarchy path.

Just use something like

        // ...
        if (sender != this)
        {
            return;
        }
        // Your handler code goes here ...
        args.Handled = true;
        // ...

in your handler code.

banzai
Bubbling would cause *different handlers* up the UI element hierarchy to be invoked for an event. It should **not** cause the same handler to be called multiple times per event.
Gishu
Bubbling was the cause in my case - it was a program written with one of the early versions of WPF. Mayhappen MS has changed something in current versions ?
banzai
Another thing to your identical handler parameters. It doesn´t matter to which event you subscribe, the sender is always the TreeView. The real sender is hidden in the RoutedEvent.OriginalSource parameter. Depending on the event sometimes it´s the TreeViewItem but for mouse events it´s the control type defined in your TreeViewItem´s (Hierarchical)DataTemplate on which the user has clicked. Probably MS has´nt overwritten the FrameworkElement implementation.
banzai
A: 

This is not actually a bubbling issue. I've seen this before. Even when you tell the event that you handled it, it continues to keep bubbling up. Except that I don't think that it's actually bubbling up, but rather firing the node above's own double click event. I could be totally wrong on that. But in either case, it's important to know that saying:

e.handled = true;

Does nothing to stop this from happening.

One way to prevent this behavior is to note that when you are double clicking, you are first single clicking and that the selected event should fire first. So while you can't stop the Double Click events from occurring, you should be able to check inside the handler to see whether the event logic should run. This example leverages that:

TreeViewItem selectedNode;

private void MouseDoubleClickEventHandler(object sender, MouseButtonEventArgs e)
{
    if(selectedNode = e.Source)
    {
        //do event logic
    }
}

private void TreeViewSelectedEventHandler(object sender, RoutedEventArgs e)
{
    selectedNode = (TreeViewItem)e.Source;
}

Sometimes however you have situations where the nodes are being selected by other beans than through the TreeView SelectedItemChanged event. In that case you can do something like this. If you happen to have a TreeView with a single declared top node, you can give that node a specific name and then do something like this:

bool TreeViewItemDoubleClickhandled;

private void MouseDoubleClickEventHandler(object sender, MouseButtonEventArgs e)
{
    if (!TreeViewItemDoubleClickhandled)
    {
        //do logic here

        TreeViewItemDoubleClickhandled = true;
    }

    if (e.Source == tviLoadTreeTop)
    {
        TreeViewItemDoubleClickhandled = false;
    }
    e.Handled = true;
}

Regardless of the method you use, the important thing is to note that for whatever reason with TreeViewItem double clicking that you can't stop the events from firing up the tree. At least I haven't found a way.

Ristogod
A: 

When a TreeViewItem is double clicked, that item is selected as part of the control behavior. Depending on the particular scenario it could be possible to say:

...
TreeViewItem tviSender = sender as TreeViewItem;

if (tviSender.IsSelected)
    DoAction();
...
Pablo