简体   繁体   中英

WPF Override / Reset Keybinding on child control

I have a window on which I have commands bound to the numpad keys like this:

<!-- Set keybindings -->
    <controls:MetroWindow.InputBindings>
        <!-- NumPad Shortcuts for selecting reasons -->
        <KeyBinding Key="NumPad0" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="0" />
        <KeyBinding Key="NumPad1" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="1" />
        <KeyBinding Key="NumPad2" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="2" />
        <KeyBinding Key="NumPad3" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="3" />
        <KeyBinding Key="NumPad4" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="4" />
        <KeyBinding Key="NumPad5" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="5" />
        <KeyBinding Key="NumPad6" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="6" />
        <KeyBinding Key="NumPad7" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="7" />
        <KeyBinding Key="NumPad8" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="8" />
        <KeyBinding Key="NumPad9" Command="{Binding OnReasonShortcutKeyPressedCommand}" CommandParameter="9" />

        <!-- Others -->
        <KeyBinding Key="Back" Command="{Binding OnReasonGoBackClickedCommand}" />
        <KeyBinding Key="Escape" Command="{Binding OnEscapeClickedCommand}" />
    </controls:MetroWindow.InputBindings>

In the backend, this is handled as:

        ICommand _onReasonShortcutKeyPressedCommand;
        public ICommand OnReasonShortcutKeyPressedCommand
        {
            get
            {
                return _onReasonShortcutKeyPressedCommand ??
                    (_onReasonShortcutKeyPressedCommand = new RelayCommand(OnReasonShortcutKeyPressedCommand_Execute));
            }
        }
        private void OnReasonShortcutKeyPressedCommand_Execute(object param)
        {
            //Find which key was presses by command param
            int keyPressed = Int32.Parse((string)param);

            // Do something bla bla bla
        }

Now, this window also contains some textboxes in which numbers have to be entered. Ofcourse, the keybindings on the window level result in the commands being triggered instead of the actual number being printed. Is there anyway in which I can override this?

Not sure whether there is better way to solve this, but my propose is to use attach property to archive this. Here is example:

In XAML you should attach new behavior (LimitBindings) to TextBox:
XAML:

<TextBox behavs:KeyBindingBehavior.LimitKeyBindings="True"></TextBox>

and create your behavior class (+ Helper method to get parent window -it should be placed somewhere else :)):

public static class KeyBindingBehavior
{
    //to keep window's bindings.
    private static InputBindingCollection windowBindings;

    public static bool GetLimitKeyBindings(DependencyObject obj)
    {
        return (bool)obj.GetValue(LimitKeyBindingsProperty);
    }

    public static void SetLimitKeyBindings(DependencyObject obj, bool value)
    {
        obj.SetValue(LimitKeyBindingsProperty, value);
    }

    public static readonly DependencyProperty LimitKeyBindingsProperty =
        DependencyProperty.RegisterAttached(
        "LimitKeyBindings",
        typeof(bool),
        typeof(KeyBindingBehavior),
        new PropertyMetadata(false, PropertyChangedCallback));

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        TextBox textBox = dependencyObject as TextBox;
        if (textBox != null)
        {
            textBox.GotKeyboardFocus += textBox_GotKeyboardFocus;
            textBox.LostKeyboardFocus += textBox_LostKeyboardFocus;
        }
    }

    static void textBox_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        var window = GetParentWindow(sender as DependencyObject);
        window.InputBindings.AddRange(windowBindings);
    }

    static void textBox_GotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        var window = GetParentWindow(sender as DependencyObject);
        windowBindings = new InputBindingCollection(window.InputBindings);
        window.InputBindings.Clear();
    }

    // This helper method should be in seperate class
    public static Window GetParentWindow(DependencyObject child)
    {
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        if (parentObject == null)
        {
            return null;
        }

        Window parent = parentObject as Window;
        if (parent != null)
        {
            return parent;
        }
        else
        {
            return GetParentWindow(parentObject);
        }
    }
}

Don't forget to add reference in XAML to point to behavior class :

xmlns:behavs="clr-namespace:WpfApplication1"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM