如何在Caliburn.Micro中绑定按键手势?

10

如何使用Caliburn.Micro将键盘手势映射到ViewModel上的操作方法?

例如,我想要实现一个选项卡界面,并且我希望我的ShellViewModel拥有一个NewTab方法,用户应该能够通过按下键盘上的Ctrl+T来调用该方法。

我知道完整的Caliburn框架支持手势,但是如何使用Caliburn.Micro来实现呢?是否有一种方式可以将操作绑定到路由命令(RoutedCommand)(因为RoutedCommands已经支持输入手势)?或者其他获得手势支持的方式?

4个回答

12

我修改了示例,以支持全局键绑定。 你只需要将以下代码添加到你的视图中:

<i:Interaction.Triggers>
        <common:InputBindingTrigger>
            <common:InputBindingTrigger.InputBinding>
                <KeyBinding Modifiers="Control" Key="D"/>
            </common:InputBindingTrigger.InputBinding>
            <cl:ActionMessage MethodName="DoTheMagic"/>
        </common:InputBindingTrigger>
    </i:Interaction.Triggers>

每当按下Ctrl+D时,方法DoTheMagic将被执行。这是修改后的InputBindingTrigger代码:

public class InputBindingTrigger : TriggerBase<FrameworkElement>, ICommand
  {
    public static readonly DependencyProperty InputBindingProperty =
      DependencyProperty.Register("InputBinding", typeof (InputBinding)
        , typeof (InputBindingTrigger)
        , new UIPropertyMetadata(null));

    public InputBinding InputBinding
    {
      get { return (InputBinding) GetValue(InputBindingProperty); }
      set { SetValue(InputBindingProperty, value); }
    }

    public event EventHandler CanExecuteChanged = delegate { };

    public bool CanExecute(object parameter)
    {
      // action is anyway blocked by Caliburn at the invoke level
      return true;
    }

    public void Execute(object parameter)
    {
      InvokeActions(parameter);
    }

    protected override void OnAttached()
    {
      if (InputBinding != null)
      {
        InputBinding.Command = this;        
        AssociatedObject.Loaded += delegate {
          var window = GetWindow(AssociatedObject);
          window.InputBindings.Add(InputBinding);
        };
      }
      base.OnAttached();
    }

    private Window GetWindow(FrameworkElement frameworkElement)
    {
      if (frameworkElement is Window)
        return frameworkElement as Window;

      var parent = frameworkElement.Parent as FrameworkElement;      
      Debug.Assert(parent != null);

      return GetWindow(parent);
    }
  }

// 在调用级别上,Caliburn无论如何都会阻止操作 这并不是真的,它仍然会触发。 - Anders
是的,它触发了,你有什么想法如何检查适当的Can方法是否允许触发该操作。 - Gregor Slavec
不好意思,我尝试调试你的代码以查找Can属性的引用,但没有成功 :/ - Anders
同意答案的方法会迅速使用户控件失效。 - ender

6

Caliburn.Micro的Actions机制是基于System.Windows.Interactivity开发的。所以,您可以基于TriggerBase创建自定义触发器来完成任何操作,包括全局键盘手势。然后,将ActionMessage插入到触发器中即可!


1
我对TriggerBase一无所知,也不知道它如何与InputGestures联系起来... 我应该从哪里开始? - Joe White
1
System.Windows.Interactivity是Blend SDK的一部分。如果您在Blend Behaviors上进行搜索,您应该会找到很多带有示例的博客。 - EisenbergEffect
2
嘿,EisenbergEffect,有没有一种方法可以进行作用域限定?我注意到当我在用户控件内这样做时,如果我具有相同的键绑定,这也会触发父窗口中的事情。 - Haacked
1
@Haacked - 我将触发器放置在自定义控件上,它将ActionMessage作用域限定在控件DataContext中的正确VM。 - codekaizen
@EisenbergEffect 你好,你们团队有没有未来计划包括对键盘操作的基本支持? - ender

0
继承Caliburn的ActionMessage(它是一个TriggerAction)并将派生的触发器附加到XAML中的KeyDown事件,然后设置ActionMessage.MethodName属性。在派生的触发器中添加一个属性,用于指定你要查找的键组合,并覆盖Invoke方法来根据该键组合进行过滤,如果键匹配,则调用base.Invoke(...)。

-1

如果您通过视图将命令传递到视图模型,您可以从视图模型控制CanExecute。我在多个Caliburn项目中使用了这种方法。可能不像使用交互那样“流畅”,但CanExecute可以正常工作。

<UserControl x:Class="MyView"
      ...
      Name="View"
>

  <UserControl.InputBindings>
    <KeyBinding Key="F5" 
                Command="{Binding RefreshCommand, ElementName=View, Mode=OneWay}" />
  </UserControl.InputBindings>

  <Button Command="{Binding Path=RefreshCommand, ElementName=View, Mode=OneWay}"/>

在你的View类中,你将命令连接到ViewModel,ViewModel被引用于MyView.DataContext属性中。
Class MyView

    Public Property RefreshCommand As _
    New RelayCommand(AddressOf Refresh,
                     Function()
                         If ViewModel Is Nothing Then
                             Return False
                         Else
                             Return ViewModel.CanRefresh
                         End If
                     End Function)

    Private Sub Refresh()
        ViewModel.Refresh()
    End Sub

    Private ReadOnly Property ViewModel As MyViewModel
        Get
            Return DirectCast(DataContext, MyViewModel)
        End Get
    End Property

End Class

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