How to bind ApplicationCommands to a ViewModel?
I have resolved this using Behaviors attached to the TreeView. The TreeViewItems or Templates to not seem to get the commands routed to them. Fortunately, the TreeView also has a SelectedItem property that can be used to get the ViewModel!
(Behaviors are conceptually similar to the solution in the link in @Natxo's answer, but it doesn't resolve everything.)
The Behavior class:
public class TreeViewClipboardBehavior : Behavior<TreeView>{ protected override void OnAttached() { base.OnAttached(); CommandBinding CopyCommandBinding = new CommandBinding( ApplicationCommands.Copy, CopyCommandExecuted, CopyCommandCanExecute); AssociatedObject.CommandBindings.Add(CopyCommandBinding); CommandBinding CutCommandBinding = new CommandBinding( ApplicationCommands.Cut, CutCommandExecuted, CutCommandCanExecute); AssociatedObject.CommandBindings.Add(CutCommandBinding); CommandBinding PasteCommandBinding = new CommandBinding( ApplicationCommands.Paste, PasteCommandExecuted, PasteCommandCanExecute); AssociatedObject.CommandBindings.Add(PasteCommandBinding); } private void CopyCommandExecuted(object target, ExecutedRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null && item.CanCopyToClipboard) { item.CopyToClipboard(); e.Handled = true; } } private void CopyCommandCanExecute(object target, CanExecuteRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null) { e.CanExecute = item.CanCopyToClipboard; e.Handled = true; } } private void CutCommandExecuted(object target, ExecutedRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null && item.CanCutToClipboard) { item.CutToClipboard(); e.Handled = true; } } private void CutCommandCanExecute(object target, CanExecuteRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null) { e.CanExecute = item.CanCutToClipboard; e.Handled = true; } } private void PasteCommandExecuted(object target, ExecutedRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null && item.CanPasteFromClipboard) { item.PasteFromClipboard(); e.Handled = true; } } private void PasteCommandCanExecute(object target, CanExecuteRoutedEventArgs e) { NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase; if (item != null) { e.CanExecute = item.CanPasteFromClipboard; e.Handled = true; } }}
The XAML
<TreeView Grid.Row="2" ItemsSource="{Binding SystemTreeRoot}"> <i:Interaction.Behaviors> <local:TreeViewClipboardBehavior/> </i:Interaction.Behaviors> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:MyViewModel}" ItemsSource="{Binding Children}"> <!-- Template content --> </HierarchicalDataTemplate></TreeView>
I believe that you are looking for CommandBindings
. I use something similar for some textboxes:
<DataTemplate x:Key="textBoxTemplate" > <TextBox> <TextBox.CommandBindings> <CommandBinding Command="ApplicationCommand.Copy" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute"> </CommandBinding> </TextBox.CommandBindings> </TextBox> </DataTemplate>
Note that PreviewCanExecute
and PreviewExecuted
are also available.
Edit: Check out the sample here to make it MVVM compliant.