Le funzionalità tipiche di un applicazione WinForm (ad esempio il Copia/Incolla) sono normalmente implementate sottoscrivendo l'evento Click generato da un menu o dall'equivalente pulsante nella toolbar. A seconda del contesto di esecuzione è poi possibile che l'evento venga trattato diversamente, ad esempio copiando del testo in un caso oppure un oggetto nell' altro.
In WPF le cose sono gestite diversamente: Anzichè mappare i clicks provenienti dai controlli è stato introdotto il concetto di comando con lo scopo di separare nettamente l'esecuzione dal relativo chiamante come indicato nel pattern Command.
Un comando può essere associato ad un FrameworkElement che quindi scatenerà un azione che percorrerà tutto il Logical Tree sottoforma di RoutedEvent alla ricerca di un elemento che lo gestisca fino al raggiungimento del controllo attivo in quel momento.
I comandi tipici di ogni applicazione (New,Copy, Paste...) sono resi disponibili dalla classe ApplicationCommands mentre altre tipologie (Navigate Next, Back...)sono esposte dalle classi ComponentsCommands, EditCommands e MediaCommands, inoltre alcuni controlli come la TextBox sanno già gestire alcune azioni tipici come ad esempio Copia e Incolla.
Tutto questo significa che lo XAML che implementa la funzionalità di copia e incolla per le textbox presenti in una finestra è:

 <StackPanel>
   <Menu>
      <MenuItem Command="ApplicationCommands.Copy" />
      <MenuItem Command="ApplicationCommands.Paste" />
   </Menu>
   <TextBox/>
   <TextBox/>
</StackPanel>

Resta ora da capire come intercettare la richiesta di esecuzione di uno specifico comando, o come viene indicato in WPF, di un RoutedCommand.
Il link tra comando e gestore è la classe CommandBinding mentre il contesto di esecuzione è la collezione CommandBindings esposta da ogni UIElement.
Ad esempio, volendo gestire il comando Stop quando txt2 ha il focus ,lo XAML da scrivere è:

<MenuItem x:Name="Menu1" Command="ApplicationCommands.Stop" />

<TextBox x:Name="txt2">
  <TextBox.CommandBindings>
     <CommandBinding Command="ApplicationCommands.Stop" Executed="ExecStop" />
   </TextBox.CommandBindings>
</TextBox>

void ExecStop (object sender, ExecutedRoutedEventArgs e){ MessageBox.Show("Stop");}

Lo snippet riportato indica che quando il comando Stop generato da Menu1 raggiungerà txt2 vogliamo venga eseguito il metodo ExecStop.
Nel caso volessimo centralizzare a livello di Window la gestione del comando, l'operazione da eseguire è quella di spostare il commandbinding dalla textbox alla collezione CommandBindings dell'oggetto parent Window, ovvero:

<Window.CommandBindings>
   <CommandBinding Command="ApplicationCommands.Stop" Executed="ExecStop" />
</Window.CommandBindings> 

In questo caso ExecStop verrà eseguito indipendentemente dal controllo selezionato.
Ad un comando è possibile associare una combinazione di tasti (definita KeyGesture in WPF) creando un oggetto InputBinding il quale raggruppa tasti e relativo comando e aggiungendolo alla collezione InputBindings dell'oggetto che la intercetterà come in questo esempio dove il comando Stop è anche associato alla combinazione CTRL+S.

<Window.InputBindings>
  <KeyBinding Key="S" Modifiers="Control" Command="ApplicationCommands.Stop" />
</Window.InputBindings>
 

Ha senso che la voce di menu associata ad un comando sia attiva se questo non è accessibile?, evidentemente no, ecco perchè gli items associati ad un comando hanno la propria abilitazione dipendente dal comando stesso.
Ipotizziamo il caso di un pulsante che deve essere attivo solo quando la relativa textbox contiene del testo, lo XAML equivalente è:

<TextBox x:Name="txt1" />

<Button Command="ApplicationCommands.Stop" CommandParameter="{Binding ElementName=txt1,Path=Text}" Content="Send">
  <Button.CommandBindings>
     <CommandBinding Command="ApplicationCommands.Stop" Executed="ExecStop" CanExecute="QueryStop" />
  </Button.CommandBindings>

</Button>

private void QueryStop (object sender, CanExecuteRoutedEventArgs e)
{
  e.CanExecute = !string.IsNullOrEmpty(e.Parameter as string);
  e.Handled = true;
}

 

Non entro nei dettagli ma ciò che conta è che il metodo QueryStop al quale, attraverso la proprietà CommandParameter del RoutedCommand viene passato il contenuto della textbox, viene utilizzato dal button per determinare la propria abilitazione.
Finora abbiamo utilizzato esclusivamente i comandi predefiniti di WPF ma ciò non significa che non sia possibile definirne dei propri e utilizzarli come mostrato finora, ad esempio qui sotto ho creato un nuovo comando ClearAll associandolo alla combinazione CTRL+P.

public class MyCommands {
   public static RoutedUICommand ClearAll;

   static MyCommands () {
      InputGestureCollection ic = new InputGestureCollection();
      ic.Add(new KeyGesture(Key.P,ModifierKeys.Control));
      ClearAll = new RoutedUICommand("ClearAll", "clear", typeof(FrameworkElement),ic); }

Il relativo XAML è:

<Window
  ...
  xmlns:c="clr-namespace:Code22_Commanding" />
  <Window.CommandBindings>
    <CommandBinding Command="c:MyCommands.ClearAll" Executed="ClearAll" CanExecute="OnCanClearAll" />
  </Window.CommandBindings>
  ...
 
<MenuItem Command="c:MyCommands.ClearAll"/>
</Window>

void ClearAll (object sender, ExecutedRoutedEventArgs e) {MessageBox.Show("Clear all invoked");}

private void OnCanClearAll (object sender, CanExecuteRoutedEventArgs e) {
  e.CanExecute = true; //Comando sempre disponibile...
  e.Handled = true; }

In questo specifico caso ho usato un RoutedUICommand il quale arricchisce il RoutedCommand di una proprietà Text che viene utilizzata dai MenuItems per visualizzare automaticamente il nome del comando come voce di menu.