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

时间:2014-10-13 07:19:35

标签: c# wpf xaml key-bindings

我有一个窗口,我有命令绑定到小键盘键,如下所示:

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

现在,此窗口还包含一些必须输入数字的文本框。当然,窗口级别的键绑定导致触发命令而不是打印的实际数字。无论如何我可以覆盖它吗?

1 个答案:

答案 0 :(得分:0)

不确定是否有更好的解决方法,但我的建议是使用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"