【问题标题】:Keybinding a RelayCommand键绑定 RelayCommand
【发布时间】:2010-11-04 16:03:24
【问题描述】:

我在我的应用程序中使用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 的最佳方法是什么?

【问题讨论】:

    标签: wpf mvvm key-bindings


    【解决方案1】:

    我认为您不能从 XAML 中执行此操作,这正是您描述的原因。

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

    这是我的一个项目中的示例代码行:

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      【解决方案3】:

      您可以继承 KeyBinding,添加一个设置 Command 属性的 CommandBinding 依赖属性,然后像任何其他输入绑定一样将其添加到 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>
      

      【讨论】:

      • keyBinding.Command = e.NewValue; 需要一个演员所以它应该像keyBinding.Command = (ICommand)e.NewValue; 对吗??
      【解决方案4】:

      您可以使用 CommandReference 类。

      非常优雅的代码,工作起来就像一个魅力。

      看看:How do I associate a keypress with a DelegateCommand in Composite 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 项的集合,并将它们添加到我窗口后面代码中的窗口 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>
          

          问候,

          蒂姆·霍顿

          【讨论】:

          • 关于 ViewModel 中的 RelayCommands 而不是 RoutedCommands 的问题。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-23
          • 2012-03-09
          • 1970-01-01
          • 2015-06-07
          • 2014-09-29
          • 2013-02-19
          • 1970-01-01
          相关资源
          最近更新 更多