Привязка клавиш к RelayCommand

Я использую в своем приложении 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?


person Joe White    schedule 21.06.2009    source источник


Ответы (6)


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

person jbe    schedule 05.10.2009
comment
Привязка свойства Command класса KeyBinding в .NET 4.0 описана в статье по адресу tomlev2.wordpress.com/2009/10/26/ - person M. Dudley; 20.04.2010
comment
Вышеупомянутая ссылка перемещена на thomaslevesque.com/2009/ 26.10 / - person avenmore; 02.01.2015

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

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

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

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

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

person Mark Seemann    schedule 21.06.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>
person Cameron MacFarland    schedule 28.09.2009
comment
keyBinding.Command = e.NewValue; нужен актерский состав, поэтому он должен быть похож на keyBinding.Command = (ICommand)e.NewValue; Верно ?? - person Ankesh; 05.10.2011

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

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

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

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

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

Я создаю привязку 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);
     }

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

person Aran Mulholland    schedule 25.09.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>

С уважением,

Тим Хотон

person Community    schedule 13.07.2009
comment
Вопрос о RelayCommands в ViewModel, а не о RoutedCommands. - person Mike Eshva; 18.06.2012