绑定RelayCommand的按键映射

27

我正在使用在我的应用程序中使用RelayCommand。它非常适合将代码放在ViewModel中,但如何将按键绑定到命令呢?

RoutedUICommand有其InputGestures属性,使得按下按键时自动调用该命令。(作为额外的奖励,它甚至可以使菜单项中的按键显示。)不幸的是,没有可重用的接口来获取RoutedUICommand的额外属性,因此我无法创建一个获得相同魔力的RelayUICommand。

我已经尝试使用InputBindings:

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

但这会导致运行时异常,因为KeyBinding.Command不是一个依赖属性。(实际上,它抱怨的是KeyBinding甚至不是DependencyObject。)而且,由于我的RelayCommand是ViewModel上的属性(与RoutedUICommand设计用于的静态字段相反),数据绑定是我知道的唯一引用它的XAML方式。

你们是如何解决这个问题的?绑定按键到RelayCommand的最佳方法是什么?

6个回答

17

我认为你无法通过XAML实现这一点,正如你所描述的那样。

最终我在代码后台完成了它。虽然它是代码,但只有一行代码,而且仍然相当声明性,所以我可以接受。但是,我真的希望在下一个版本的WPF中解决这个问题。

以下是我项目中的示例代码:

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

在这种情况下,SynchronizeCommand是一个RelayCommand实例,并且(显然)F9触发它。


14

KeyBinding类的Command属性不支持数据绑定。这个问题将在.NET 4.0中解决,您应该能够在即将发布的.NET 4.0 Beta 2版本中看到。


10
.NET 4.0中KeyBinding类的Command属性绑定在http://tomlev2.wordpress.com/2009/10/26/vs2010-binding-support-in-inputbindings/文章中有详细描述。 - sourcenouveau
1
以上链接已经移动到http://www.thomaslevesque.com/2009/10/26/vs2010-binding-support-in-inputbindings/。 - avenmore

10

你可以创建一个继承于 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>

1
keyBinding.Command = e.NewValue; 需要进行强制类型转换,所以应该写成 keyBinding.Command = (ICommand)e.NewValue; 对吗? - Ankesh

2
您可以使用CommandReference类。
非常优雅的代码,效果非常好。
请看:如何将按键与Composite WPF中的DelegateCommand关联? 它与RelayCommands的工作方式相同,但不会更新您的CanExecutes,因为CommandReference不使用调用CommandManager.RequerySuggested。 要实现自动CanExecute重新评估,您只需要在CommandReference类内进行以下更改即可。
public event EventHandler CanExecuteChanged
{
     add { CommandManager.RequerySuggested += value; }
     remove { CommandManager.RequerySuggested -= value; }
}

0
我在我的视图模型中创建了一个键绑定,将命令和键链接起来,就像这样。
        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);
     }

在代码后端做一些事情是不好的形式,我知道,但我还不知道如何进行绑定,不过我仍在努力。 :) 这唯一没有给我的是菜单中的键命令修饰符列表,但这将会实现。


-1
假设您的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>

敬礼,

蒂姆·霍顿


关于ViewModel中的RelayCommands而不是RoutedCommands的问题。 - Mike Eshva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接