Подтвердить что ты не робот

Привязка к RelayCommand

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

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?

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

Вы можете подклассифицировать 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>

Ответ 4

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

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

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

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

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

Ответ 5

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

        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 в моем корне модели View Model и добавляю их в окна InputBindings в моем оконном коде за

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

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

Ответ 6

Предполагая, что ваши 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>

Привет,

Тим Хотон