Связывание ключей RelayCommand - PullRequest
27 голосов
/ 21 июня 2009

Я использую RelayCommand в моем приложении. Он отлично подходит для помещения кода в модель представления, но как мне связать нажатия клавиш с моей командой?

RoutedUICommand имеет свойство InputGestures, которое позволяет автоматически вызывать команду при нажатии клавиши. (В качестве дополнительного бонуса он даже отображает нажатие клавиш в MenuItem.) К сожалению, нет никакого многоразового интерфейса для дополнительных свойств RoutedUICommand, поэтому я не могу создать RelayUICommand, который получает ту же магию.

Я уже пытался использовать InputBindings:

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

Но это вызывает у меня исключение во время выполнения, потому что KeyBinding.Command не является свойством зависимости. (На самом деле, на что он жалуется, так это того, что KeyBinding не является даже DependencyObject.) И поскольку моя RelayCommand является свойством моего ViewModel (в отличие от статического поля, для которого предназначена RoutedUICommand), привязка данных является единственным известным мне способом ссылаться на него из XAML.

Как вы, ребята, решили это? Какой лучший способ связать нажатие клавиши с RelayCommand?

Ответы [ 6 ]

17 голосов
/ 21 июня 2009

Я не думаю, что вы можете сделать это из XAML, именно по тем причинам, которые вы описываете.

Я закончил делать это в коде позади. Хотя это код, это всего лишь одна строка кода, и все же довольно декларативная, так что я могу с этим жить. Однако я очень надеюсь, что это будет решено в следующей версии WPF.

Вот пример строки кода из одного из моих проектов:

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

SynchronizeCommand в этом случае является экземпляром RelayCommand, и (очевидно) F9 запускает его.

14 голосов
/ 05 октября 2009

Свойство Command класса KeyBinding не поддерживает привязку данных. Эта проблема будет решена в .NET 4.0, и вы сможете увидеть ее в следующей версии .NET 4.0 Beta 2.

10 голосов
/ 29 сентября 2009

Вы можете создать подкласс KeyBinding, добавить свойство зависимостей CommandBinding, которое устанавливает свойство Command, а затем добавить его в 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>
2 голосов
/ 11 апреля 2011

Вы можете использовать класс CommandReference.

Очень элегантный код и работает как шарм.

Взгляните на: Как связать нажатие клавиши с DelegateCommand в составном WPF?

Он работает так же с RelayCommands, но не обновляет ваши CanExecutes, так как CommandReference не использует call CommandManager.RequerySuggested Все, что вам нужно сделать для автоматической переоценки CanExecute, это сделать следующее изменение внутри класса CommandReference

public event EventHandler CanExecuteChanged
{
     add { CommandManager.RequerySuggested += value; }
     remove { CommandManager.RequerySuggested -= value; }
}
0 голосов
/ 25 сентября 2009

Я создаю привязку Key в моей модели представления, которая связывает команду и Key следующим образом:

        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;

затем я создаю коллекцию элементов InputBinding в корне моей модели представления и добавляю их в окна InputBindings в коде моего окна

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

его плохая форма - делать вещи в коде, я знаю, но я пока не знаю, как сделать связывание, однако я все еще работаю над этим. :) Единственное, что мне дает этот список, это список ключевых модификаторов команд в меню, но это будет впереди.

0 голосов
/ 13 июля 2009

При условии, что ваши RoutedCommands определены статически:

#region DeleteSelection

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

    #endregion

Свяжите в XAML таким образом:

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

С уважением,

Тим Хотон

...