子控件上的WPF覆盖/重置键绑定

本文关键字:绑定 覆盖 控件 WPF | 更新日期: 2023-09-27 18:26:16

我有一个窗口,上面有绑定到numpad键的命令,如下所示:

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

在后端,这被处理为:

        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
        }

现在,这个窗口还包含一些必须在其中输入数字的文本框。当然,窗口级别的键绑定会导致触发命令,而不是打印实际数字。有什么我可以推翻的吗?

子控件上的WPF覆盖/重置键绑定

不确定是否有更好的方法来解决这个问题,但我的建议是使用attach属性来存档这个问题。以下是示例:

在XAML中,您应该将新行为(LimitBindings)附加到TextBox:
XAML:

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

并创建您的行为类(+Helper方法来获取父窗口-它应该放在其他地方:):

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);
        }
    }
}

不要忘记在XAML中添加指向行为类的引用:

xmlns:behavs="clr-namespace:WpfApplication1"