2009-06-21 5 views
27

Utilizzo la RelayCommand nella mia app. È fantastico per inserire il codice nel viewmodel, ma come faccio a collegare i tasti al mio comando?Legatura di tasti a RelayCommand

RoutedUICommand ha la proprietà InputGestures, che rende automaticamente invocato il comando quando preme il tasto. (Come bonus aggiuntivo, rende anche la visualizzazione della sequenza di tasti nel MenuItem.) Sfortunatamente, non c'è un'interfaccia riutilizzabile per le proprietà extra di RoutedUICommand, quindi non posso creare un RelayUICommand che abbia la stessa magia.

Ho già provato ad utilizzare InputBindings:

<Window.InputBindings> 
    <KeyBinding Key="PageUp" Command="{Binding SelectPreviousLayerCommand}"/> 
</Window.InputBindings> 

Ma che mi fa un'eccezione di runtime, perché KeyBinding.Command non è una proprietà di dipendenza. (In realtà, ciò che si lamenta è che KeyBinding non è nemmeno un DependencyObject.) E poiché il mio RelayCommand è una proprietà sul mio ViewModel (al contrario del campo statico per cui RoutedUICommand è progettato), il database è l'unico modo che conosco di fare riferimento da XAML.

Come avete risolto questo ragazzi? Qual è il modo migliore per associare un tasto a un RelayCommand?

risposta

14

La proprietà Comando della classe KeyBinding non supporta l'associazione dati. Questo problema verrà risolto in .NET 4.0 e dovresti essere in grado di vederlo nella prossima versione di .NET 4.0 Beta 2.

+10

Il binding della proprietà Command della classe KeyBinding in .NET 4.0 è descritto in un articolo all'indirizzo http://tomlev2.wordpress.com/2009/10/26/vs2010-binding-support-in-inputbindings/ –

+1

Il link precedente si è spostato a http://www.thomaslevesque.com/2009/10/26/vs2010-binding-support-in-inputbindings/ – avenmore

17

Non penso che tu possa farlo da XAML, esattamente per le ragioni che descrivi.

Ho finito per farlo nel code-behind. Sebbene sia un codice, è solo una singola riga di codice, e ancora piuttosto dichiarativo, quindi posso conviverci. Tuttavia, mi auguro davvero che questo sia risolto nella prossima versione di WPF.

Ecco una riga di codice di esempio da uno dei miei progetti:

this.InputBindings.Add(new KeyBinding(
    ((MedicContext)this.DataContext).SynchronizeCommand, 
    new KeyGesture(Key.F9))); 

SynchronizeCommand in questo caso è un esempio di RelayCommand, e (ovviamente) F9 attiva.

-1

Assumendo che il RoutedCommands sono definiti in modo statico:

#region DeleteSelection 

    /// <summary> 
    /// The DeleteSelection command .... 
    /// </summary> 
    public static RoutedUICommand DeleteSelection 
     = new RoutedUICommand("Delete selection", "DeleteSelection", typeof(ChemCommands)); 

    #endregion 

Bind in XAML così:

<Canvas.InputBindings> 
    <KeyBinding Key="Delete" Command="{x:Static Controls:ChemCommands.DeleteSelection}" /> 
</Canvas.InputBindings> 

saluti,

Tim Haughton

+0

il qustion su RelayCommands in un ViewModel e non si tratta di RoutedCommands. –

0

crea un legame chiave a mio avviso modello che collega il comando e la chiave in questo modo

 this.KeyBinding = new KeyBinding(); 
     //set the properties 
     this.KeyBinding.Command = this.Command; 
     this.KeyBinding.Key = this.Key; 
     //modifier keys may or may not be set 
     this.KeyBinding.Modifiers = this.ModifierKeys; 

poi creo una collezione di oggetti InputBinding nella mia radice Vista Modello e aggiungerli alle finestre InputBindings nel codice di mia finestra dietro

 foreach (var item in applicationViewModel.InputBindingCollection) { 
     this.InputBindings.Add(item); 
    } 

sua forma male di fare cose nel codice dietro lo so , ma non so ancora come fare il binding, comunque sto ancora lavorando su di esso. :) L'unica cosa che questo doent mi dà è una lista modif del comando tasti nel menu, ma quello deve venire.

10

È possibile creare una sottoclasse di KeyBinding, aggiungere una proprietà di dipendenza CommandBinding che imposta la proprietà Command e quindi aggiungerla a XAML come qualsiasi altro binding di input.

public class RelayKeyBinding : KeyBinding 
{ 
    public static readonly DependencyProperty CommandBindingProperty = 
     DependencyProperty.Register("CommandBinding", typeof(ICommand), 
     typeof(RelayKeyBinding), 
     new FrameworkPropertyMetadata(OnCommandBindingChanged)); 
    public ICommand CommandBinding 
    { 
     get { return (ICommand)GetValue(CommandBindingProperty); } 
     set { SetValue(CommandBindingProperty, value); } 
    } 

    private static void OnCommandBindingChanged(
     DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var keyBinding = (RelayKeyBinding)d; 
     keyBinding.Command = (ICommand)e.NewValue; 
    } 
} 

XAML:

<Window.InputBindings> 
    <RelayKeyBinding 
     Key="PageUp" 
     CommandBinding="{Binding SelectPreviousLayerCommand}" /> 
</Window.InputBindings> 
+1

'keyBinding.Command = e.NewValue;' richiede un cast quindi dovrebbe essere come 'keyBinding.Command = (ICommand) e.NewValue;' Giusto ?? – Ankesh

2

È possibile utilizzare la classe CommandReference.

Codice molto elegante e funziona come un fascino.

Date un'occhiata a: How do I associate a keypress with a DelegateCommand in Composite WPF?

Funziona lo stesso con RelayCommands, ma non aggiornerà i tuoi CanExecutes dal momento che il CommandReference non usa chiamare CommandManager.RequerySuggested Tutto quello che devi fare per raggiungere automatica CanExecute rivalutazione è fare la seguente modifica all'interno della classe CommandReference

public event EventHandler CanExecuteChanged 
{ 
    add { CommandManager.RequerySuggested += value; } 
    remove { CommandManager.RequerySuggested -= value; } 
}