Search code examples
c#wpfxaml

How to bind a value to the "Gesture" property of the MouseBinding class? – WPF XAML


I am currently trying to add the following line of code to my XAML file:

<MouseBinding Command="helix:ViewportCommands.Rotate" Gesture="{Binding ViewportRotateGesture}" />

The problem is that this doesn't work. Whenever I try to bind a string to the "Gesture" property, I get the following exception:

System.Windows.Markup.XamlParseException: 'A 'Binding' cannot be set on the 'Gesture' property of type 'MouseBinding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.'

Using the "MouseAction" property instead of the "Gesture" property does work, however this doesn’t allow you to add any modifiers. Does anybody know how to bind a mouse gesture in combination with a modifier (for example Shift+LeftClick)?


Solution

  • This is not a DependencyProperty, but a normal CLR property. You can't bind him. See public virtual InputGesture Gesture.

    You can create a Behavior or an Attached Property for this purpose.

    Example:

    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace Core2022.SO.Chris.AttachedProperties
    {
        public static class InputBinding
        {
            /// <summary>Returns the value of the attached property Gesture for the <paramref name="inputBinding"/>.</summary>
            /// <param name="inputBinding"><see cref="System.Windows.Input.InputBinding"/>  whose property value will be returned.</param>
            /// <returns>Property value <see cref="InputGesture"/>.</returns>
            public static InputGesture GetGesture(System.Windows.Input.InputBinding inputBinding)
            {
                return (InputGesture)inputBinding.GetValue(GestureProperty);
            }
    
            /// <summary>Sets the value of the Gesture attached property to <paramref name="inputBinding"/>.</summary>
            /// <param name="inputBinding"><see cref="System.Windows.Input.InputBinding"/> whose property is setting to a value..</param>
            /// <param name="value"><see cref="InputGesture"/> value for property.</param>
            public static void SetGesture(System.Windows.Input.InputBinding inputBinding, InputGesture value)
            {
                inputBinding.SetValue(GestureProperty, value);
            }
    
            /// <summary><see cref="DependencyProperty"/> for methods <see cref="GetGesture(System.Windows.Input.InputBinding)"/>
            /// and <see cref="SetGesture(System.Windows.Input.InputBinding, InputGesture)"/>.</summary>
            public static readonly DependencyProperty GestureProperty =
                DependencyProperty.RegisterAttached(
                    nameof(GetGesture).Substring(3),
                    typeof(InputGesture),
                    typeof(InputBinding),
                    new PropertyMetadata(null, OnGestureChanged));
    
            private static void OnGestureChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                if (d is not System.Windows.Input.InputBinding inputBinding)
                    throw new NotImplementedException($"Implemented only for the \"{typeof(System.Windows.Input.InputBinding).FullName}\" class");
    
                inputBinding.Gesture = (InputGesture)e.NewValue;
            }
        }
    }
    
    <MouseBinding Command="helix:ViewportCommands.Rotate"
                  ap:InputBinding.Gesture="{Binding ViewportRotateGesture}"/>