How can I bind key gestures in Caliburn.Micro?

前端 未结 5 1277
一个人的身影
一个人的身影 2020-12-30 08:47

How can I get Caliburn.Micro to map a key gesture to an action method on my ViewModel?

For example, I want to implement a tabbed interface, and I want my ShellViewMo

相关标签:
5条回答
  • 2020-12-30 09:23

    You can do it by deriving from System.Windows.Interactivity.TriggerBase. Here is an example.

    0 讨论(0)
  • 2020-12-30 09:26

    If you marshal a command through the View to the View Model you can control the CanExecute from the View Model. I've been using this method in multiple Caliburn projects. Might not be as "slick" as using Interactivity, but CanExecute works.

    <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}"/>
    

    In your View class, you wire the command to the View Model which is referenced in the MyView.DataContext property.

    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
    
    0 讨论(0)
  • 2020-12-30 09:29

    Caliburn.Micro's Actions mechanism is built on top of System.Windows.Interactivity. So, you can create a custom trigger based on TriggerBase to do whatever you want, including global keyboard gestures. Then, just plug the ActionMessage into your trigger and viola!

    0 讨论(0)
  • 2020-12-30 09:30

    Inherit from Caliburn's ActionMessage (which is a TriggerAction) and attach the derived trigger to the KeyDown event in XAML and set the ActionMessage.MethodName property. Add a property to the derived trigger of what key combination you are looking for and override the Invoke method to filter by that key combination, calling base.Invoke(...) if the key matches.

    0 讨论(0)
  • 2020-12-30 09:37

    I modified example to enable support for global key-bindings. You just need to add the folowing code to your view:

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

    And whenever Ctr+D is pressed the method DoTheMagic will be exexuted. Here is the modified InputBindingTrigger code:

    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 讨论(0)
提交回复
热议问题