KeyBinding eine RelayCommand
-
06-07-2019 - |
Frage
Ich bin mit dem RelayCommand in meiner app. Es ist toll, den Code in dem Ansichtsmodell für die Umsetzung, aber wie kann ich binden Tastenanschläge an meinen Befehl?
RoutedUICommand hat seine InputGestures Eigenschaft, die den Befehl macht automatisch aufgerufen werden, wenn ich die Tasten drücken. (Als zusätzlichen Bonus, es macht sogar die Tastenanzeige im MenuItem.) Leider gibt es keine wiederverwendbare Schnittstelle für RoutedUICommand die zusätzlichen Eigenschaften, also kann ich nicht RelayUICommand machen, die die gleiche Magie wird.
Ich habe schon versucht, mit Inputbindings:
<Window.InputBindings>
<KeyBinding Key="PageUp" Command="{Binding SelectPreviousLayerCommand}"/>
</Window.InputBindings>
Aber das wird mir eine Laufzeitausnahme, weil KeyBinding.Command keine Abhängigkeitseigenschaft ist. (Eigentlich ist es, was beschwert ist darüber KeyBinding ist nicht einmal ein DependencyObject.) Und da mein RelayCommand eine Eigenschaft auf meinem Viewmodel ist (im Gegensatz zu dem statischen Feld entgegengesetzt, der RoutedUICommand konzipiert ist), Datenbindung ist der einzige Weg, ich kenne verweisen sie von XAML.
Wie haben ihr gelöst das? Was ist der beste Weg, um einen Tastendruck auf eine RelayCommand zu binden?
Lösung
Die Command-Eigenschaft der KeyBinding Klasse bietet keine Unterstützung für die Datenbindung. Dieses Problem wird .NET 4.0 gelöst werden, und Sie sollten sie sehen können, in dem kommenden .NET 4.0 Beta 2-Version.
Andere Tipps
Ich glaube nicht, dass Sie dies von XAML tun, für genau die Gründe, die Sie beschreiben.
Ich landete es in dem Code-Behind zu tun. Obwohl es Code ist, ist es nur eine einzige Zeile Code, und noch eher deklarativen, so kann ich damit leben. Allerdings würde Ich hoffe wirklich, 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.
Sie könnten KeyBinding Unterklasse, fügen Sie eine CommandBinding
Abhängigkeitseigenschaft, die die Command-Eigenschaft setzt, und fügen Sie es dann wie jede andere Eingabe Bindung an XAML.
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>
Sie können die CommandReference Klasse.
Sehr elegant Code und wirkt wie ein Zauber.
Schauen Sie sich auf: Wie verbinde ich einen Tastendruck mit einem DelegateCommand Composite WPF?
Es funktioniert genauso mit RelayCommands, aber es wird nicht Ihren CanExecutes aktualisieren, da der CommandReference nicht Anruf CommandManager.RequerySuggested
nicht verwendet
Alles, was Sie tun müssen, automatische CanExecute
Umwertung zu erreichen, ist in der CommandReference Klasse die folgende Änderung tun
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Ich schaffe eine Schlüssel Bindung meiner Ansicht nach Modell, das den Befehl und den Schlüssel wie so
Links 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 Einzelteilen in meiner Ansicht Modell Wurzel und fügen Sie sie zu den Fenstern Inputbindings in Code meines Fensters 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 die Bindung noch zu tun, aber im noch daran zu arbeiten. :) Das einzige, was diese doent mir geben, ist ein Tastenbefehl Modifikator Liste im Menü, aber das ist zu kommen.
Ihre RoutedCommands Unter der Annahme definiert sind statisch:
#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