wpf mvvm routed-commands

wpf - ¿Cómo vincular ApplicationCommands a un ViewModel?



mvvm routed-commands (2)

He utilizado con éxito algunos comandos personalizados usando MVVM-Light, pero quiero que mi aplicación responda a los ApplicationCommands estándar, no solo a nivel de ventana, sino también a nivel de artículo detallado.

Tengo un TreeView que quiero copiar y pegar nodos. Cada TreeViewItem tiene su propio ViewModel, y se muestran a través de HierarchicalDataTemplates en XAML ya que hay varios tipos diferentes. Implementé métodos para copiar, pegar, así como CanCopy y CanPaste en mis clases de ViewModel. Si corresponde, podría implementar MVVM-Light RelayCommands apuntando a estos fácilmente, pero eso no parece correcto.

Me gustaría acceder a los comandos usando un menú, Ctrl + C y Ctrl + V, o eventualmente un menú contextual. Tampoco quiero romper la funcionalidad copiar / pegar para otros elementos en mi UI, como los cuadros de texto. Parece apropiado utilizar los ApplicationCommands incorporados para este propósito. Sin embargo, solo veo ejemplos de que estos se manejan en un código de usuario subyacente. No tengo (o de otro modo necesito) un UserControl, ni eso realmente está siguiendo a MVVM.

¿Hay alguna manera de vincular los comandos ApplicationCommand.Copy y ApplicationCommand.Paste a mis ViewModels, es decir, en las plantillas de datos?


Creo que estás buscando CommandBindings . Uso algo similar para algunos cuadros de texto:

<DataTemplate x:Key="textBoxTemplate" > <TextBox> <TextBox.CommandBindings> <CommandBinding Command="ApplicationCommand.Copy" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute"> </CommandBinding> </TextBox.CommandBindings> </TextBox> </DataTemplate>

Tenga en cuenta que PreviewCanExecute y PreviewExecuted también están disponibles.

Editar: revise la muestra aquí para que sea compatible con MVVM.


Lo he resuelto usando Comportamientos adjuntos a TreeView. TreeViewItems o plantillas para que no parezcan obtener los comandos dirigidos a ellos. Afortunadamente, TreeView también tiene una propiedad SelectedItem que se puede usar para obtener ViewModel.

(Los comportamientos son conceptualmente similares a la solución en el enlace en la respuesta de @ Natxo, pero no resuelve todo).

La clase de Comportamiento:

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

El 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>