2009-06-21 15 views
27

Ich benutze die RelayCommand in meiner App. Es ist großartig, den Code in das Viewmodel zu schreiben, aber wie verbinde ich Tastenanschläge mit meinem Befehl?Keybinding ein RelayCommand

RoutedUICommand hat seine InputGestures-Eigenschaft, wodurch der Befehl automatisch aufgerufen wird, wenn ich den Tastendruck drücke. (Als zusätzlichen Bonus macht es sogar die Tastendruckanzeige im MenuItem.) Leider gibt es keine wiederverwendbare Schnittstelle für die zusätzlichen Eigenschaften von RoutedUICommand, so dass ich keinen RelayUICommand erstellen kann, der die gleiche Magie bekommt.

Ich habe bereits versucht Inputbindings mit:

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

Aber das wird mir eine Laufzeitausnahme, weil KeyBinding.Command keine Abhängigkeitseigenschaft ist. (Eigentlich beschwert es sich, dass KeyBinding nicht einmal ein DependencyObject ist.) Und da mein RelayCommand eine Eigenschaft in meinem ViewModel ist (im Gegensatz zu dem statischen Feld, für das RoutedUICommand bestimmt ist), ist die Datenbindung die einzige mir bekannte Methode um es von XAML zu referenzieren.

Wie habt ihr das gelöst? Was ist der beste Weg, um einen Tastenanschlag an einen RelayCommand zu binden?

Antwort

14

Die Command-Eigenschaft der KeyBinding Klasse keine Daten unterstützen verbindlich. Dieses Problem wird in .NET 4.0 gelöst und Sie sollten es in der kommenden .NET 4.0 Beta 2 Version sehen können.

+10

Das Binden der Command-Eigenschaft der KeyBinding-Klasse in .NET 4.0 ist in einem Artikel unter http://tomlev2.wordpress.com/2009/10/26/vs2010-binding-support-in-inputbindings/ beschrieben. –

+1

Der obige Link wurde verschoben http://www.thomaslevesque.com/2009/10/26/vs2010-binding-support-in-inputbindings/ – avenmore

17

Ich glaube nicht, dass Sie dies aus XAML tun können, genau aus den Gründen, die Sie beschreiben.

Ich endete damit im Code-Behind. Obwohl es Code ist, ist es nur eine einzige Codezeile und immer noch ziemlich deklarativ, damit ich damit leben kann. Ich hoffe jedoch sehr, dass dies in der nächsten Version von WPF gelöst wird.

Hier ist ein Beispielcodezeile aus einem meiner Projekte:

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

SynchronizeCommand in diesem Fall ist eine Instanz RelayCommand, und (natürlich) F9 löst es.

-1

Ihre RoutedCommands Unter der Annahme, statisch definiert:

#region DeleteSelection 

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

    #endregion 

Bind in XAML so:

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

Grüße,

Tim Haughton

+0

die qustion über RelayCommands in einem Ansichtsmodell und nicht etwa RoutedCommands. –

0

ich einen Key Bindung meiner Ansicht erstellen Modell, das den Befehl und den Schlüssel wie folgt verbindet

 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; 

dann erstelle ich eine Sammlung von Inputbinding Einzelteile in meiner Ansicht Modell Wurzel und fügen Sie sie zu den Fenstern Inputbindings in Code mein Fenster hinter

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

seine schlechte Form Sachen im Code zu tun, hinter ich weiß, , aber ich weiß nicht, wie man die Bindung noch macht, aber ich arbeite immer noch daran. :) Die einzige Sache, die dieser Doent mir gibt, ist eine Schlüsselbefehlsmodifikatorliste im Menü, aber das soll kommen.

10

Sie könnten KeyBinding von der Unterklasse ableiten, eine CommandBinding-Abhängigkeitseigenschaft hinzufügen, die die Command-Eigenschaft festlegt, und sie dann wie jede andere Eingabebindung zu XAML hinzufügen.

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;' benötigt eine Umwandlung, so sollte es wie 'keyBinding.Command = (ICommand) e.NewValue sein;' Richtig? – Ankesh

2

Sie können die CommandReference-Klasse verwenden.

Sehr eleganter Code und funktioniert wie ein Charme.

Werfen Sie einen Blick auf: How do I associate a keypress with a DelegateCommand in Composite WPF?

Es funktioniert genauso mit RelayCommands, aber es wird nicht Ihre CanExecutes aktualisieren, da die CommandReference nicht nennen CommandManager.RequerySuggested verwenden Alles, was Sie tun müssen, um die automatische CanExecute Umwertung zu erreichen ist tut die folgende Änderung in der CommandReference Klasse

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