WPF/MVVM - how to handle double-click on TreeViewItems in the ViewModel? WPF/MVVM - how to handle double-click on TreeViewItems in the ViewModel? wpf wpf

WPF/MVVM - how to handle double-click on TreeViewItems in the ViewModel?


Updating my answer a bit.

I've tried alot of different approaches for this and I still feel like Attached Behaviors is the best solution. Although it might look like alot of overhead in the begining it really isn't. I keep all of my behaviors for ICommands in the same place and whenever I need support for another event it is just a matter of copy/paste and change the event in the PropertyChangedCallback.

I also added the optional support for CommandParameter.

In the designer it is just a matter of selecting the desired event

enter image description here

You can set this either on TreeView, TreeViewItem or any other place that you like.

Example. Set it on the TreeView

<TreeView commandBehaviors:MouseDoubleClick.Command="{Binding YourCommand}"          commandBehaviors:MouseDoubleClick.CommandParameter="{Binding}"          .../>

Example. Set it on TreeViewItem

<TreeView ItemsSource="{Binding Projects}">    <TreeView.ItemContainerStyle>        <Style TargetType="{x:Type TreeViewItem}">            <Setter Property="commandBehaviors:MouseDoubleClick.Command"                    Value="{Binding YourCommand}"/>            <Setter Property="commandBehaviors:MouseDoubleClick.CommandParameter"                    Value="{Binding}"/>        </Style>    </TreeView.ItemContainerStyle></TreeView>

And here is the Attached Behavior MouseDoubleClick

public class MouseDoubleClick{    public static DependencyProperty CommandProperty =        DependencyProperty.RegisterAttached("Command",        typeof(ICommand),        typeof(MouseDoubleClick),        new UIPropertyMetadata(CommandChanged));    public static DependencyProperty CommandParameterProperty =        DependencyProperty.RegisterAttached("CommandParameter",                                            typeof(object),                                            typeof(MouseDoubleClick),                                            new UIPropertyMetadata(null));    public static void SetCommand(DependencyObject target, ICommand value)    {        target.SetValue(CommandProperty, value);    }    public static void SetCommandParameter(DependencyObject target, object value)    {        target.SetValue(CommandParameterProperty, value);    }    public static object GetCommandParameter(DependencyObject target)    {        return target.GetValue(CommandParameterProperty);    }    private static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)    {        Control control = target as Control;        if (control != null)        {            if ((e.NewValue != null) && (e.OldValue == null))            {                control.MouseDoubleClick += OnMouseDoubleClick;            }            else if ((e.NewValue == null) && (e.OldValue != null))            {                control.MouseDoubleClick -= OnMouseDoubleClick;            }        }    }    private static void OnMouseDoubleClick(object sender, RoutedEventArgs e)    {        Control control = sender as Control;        ICommand command = (ICommand)control.GetValue(CommandProperty);        object commandParameter = control.GetValue(CommandParameterProperty);        command.Execute(commandParameter);    }}


I am late for this, but I just used a different solution. Once again, it might not be the best, but here is how I did that.

First of all, the previous answer from Meleak is cool, but I feel like it is very heavy to be forced to add AttachedBehaviors just for something as basic as a MouseDoubleClick. This would force me to use a new pattern in my app and would even more complicate everything.

My aim is to stay as simple as possible. Therefore I did something very basic (my example is for a DataGrid, but you can use that on a lot of different controls):

<DataGrid MouseDoubleClick="DataGrid_MouseDoubleClick">   <!-- ... --></DataGrid>

In the code-behind:

private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e){    //Execute the command related to the doubleclick, in my case Edit    (this.DataContext as VmHome).EditAppCommand.Execute(null);}

Why do I feel like it doesn't break the MVVM-pattern? Because in my opinion, the only things you should put in the code-behind are bridges to your viewModel, things very specific to your UI. In this case it just says that if you double click, fire the related command. It's almost the same than a Command="{Binding EditAppCommand}", I just simulated this behavior.

Feel free to give me your opinion on this, I'd be glad to hear some critics to this way of thinking, but for now I believe it's the easiest way to implement it without breaking MVVM.


Both Meleak and ígor's recommendations are great, but when the double click event handler is bound to TreeViewItem then this event handler is called for all of the item's parent elements (not just the clicked element). If it is not desired, here is another addition:

private static void OnMouseDoubleClick(object sender, RoutedEventArgs e){    Control control = sender as Control;    ICommand command = (ICommand)control.GetValue(CommandProperty);    object commandParameter = control.GetValue(CommandParameterProperty);    if (sender is TreeViewItem)    {        if (!((TreeViewItem)sender).IsSelected)            return;    }    if (command.CanExecute(commandParameter))    {        command.Execute(commandParameter);    }}