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

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

问题描述:

如何获取Caliburn.Micro将关键手势映射到ViewModel上的操作方法?如何在Caliburn.Micro中绑定关键手势?

例如,我想要实现一个选项卡式接口,并且我希望我的ShellViewModel具有NewTab方法,用户应该可以通过按下键盘上的Ctrl + T来调用该方法。

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

你可以通过派生System.Windows.Interactivity.TriggerBase。 Here is an example

+0

我从来没有得到这个工作,但开始再看这个,因为我现在真的需要这个。我需要将手势的菜单项集中触发。如果窗口是关注的,我希望它能触发,我该如何解决这个问题?谢谢 – Anders 2012-10-30 14:25:04

+0

如果将示例逻辑放入主窗口,它会冻结整个视图! – ender 2014-02-17 10:10:28

+0

如果您考虑,此解决方法不会真正起作用。例如,当您将命令附加到'MenuItem'并且此命令具有手势(快捷键)时,WPF将在右侧(在菜单文本之后)显示按键组合。 – JobaDiniz 2016-07-23 18:35:04

Caliburn.Micro的Actions机制建立在System.Windows.Interactivity之上。所以,你可以创建一个基于TriggerBase的自定义触发器来做你想做的任何事情,包括全局键盘手势。然后,只需将ActionMessage插入触发器和中提琴!

+1

我对TriggerBase一无所知或者它如何与InputGestures配合......我甚至可以从哪里开始? – 2010-11-15 13:01:50

+1

不是我downvote,顺便说一句。 – 2010-11-16 04:03:08

+1

System.Windows.Interactivity是Blend SDK的一部分。如果你在混合行为上进行一些搜索,你应该找到很多带有样本的博客。 – EisenbergEffect 2010-11-16 17:47:08

从Caliburn的ActionMessage(它是一个TriggerAction)继承,并将派生的触发器附加到XAML中的KeyDown事件并设置ActionMessage.MethodName属性。将属性添加到您正在查找的组合键的派生触发器中,并重写Invoke方法以按该组合键进行过滤,如果键匹配,则调用base.Invoke(...)。

我修改了example以启用对全局键绑定的支持。 你只需要如下因素代码添加到您的视图:

<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> 

每当CTR + d按下方法DoTheMagic将exexuted。下面是修改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); 
    } 
    } 
+0

//动作无论如何都被Caliburn阻止在调用级别 这不是真的,它仍然会触发 – Anders 2012-04-02 14:30:10

+0

是的,它会触发,你是否知道如果允许触发该动作,你如何检查相应的Can方法。 – 2012-05-05 21:03:08

+0

不,我试图调试你的代码来找到一个可以引用的引用,但是没有成功:/ – Anders 2012-05-06 13:30:22

如果通过查看到视图模型,你可以从视图模型控制CanExecute元帅的命令。我一直在多个Caliburn项目中使用这种方法。可能不像使用Interactivity那样“光滑”,但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类中,将命令连接到在MyView.DataContext属性中引用的View Model。

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