WPF KeyBinding吞咽键,阻止TextBox使用

时间:2015-10-14 19:00:11

标签: c# .net wpf xaml

问题概述
任何KeyBinding定义的级别高于TextBox(未指定修改键),都会阻止用户在TextBox内键入这些键。

最小XAML层次结构:

<Window>
  <UserControl>
    <Border>
      <UserControl>
        <TextBox>

最小命令/键绑定:

<UserControl.Resources>
    <RoutedUICommand x:Key="Commands.SomeCommand" />
</UserControl.Resources>
<UserControl.InputBindings>
    <KeyBinding Key="A" Command="{StaticResource Commands.SomeCommand} />
</UserControl.InputBindings>
<UserControl.CommandBindings>
    <CommandBinding Command="{StaticResource Commands.SomeCommand}" Executed="..." />
</UserControl.CommandBindings>

CommandKeyBinding是在第一个 UserControl级别定义的。因此,在此示例中,在文本框中,用户可以自由键入,直到他们按下A键,然后它就不会将字母插入文本框中。当您按下TextBox.KeyDown键(和TextBox.PreviewKeyDown)时,我可以清楚地看到AHandled = false 被触发,但这封信不会添加到文本框的文本中,TextBox.PreviewTextInput执行

我正在寻找任何建议,这些建议可能表明什么是吞咽按键并阻止它被TextBox处理,或者与我如何调试此问题有关。

编辑:
感谢Snoop,我能够清楚地看到问题。

  1. TextBox.PreviewKeyDown隧道向下并通过可视树触发,从Window开始,到TextBox结束
  2. TextBox.KeyDown气泡从TextBox开始向窗口方向返回
  3. TextBox.KeyDown通过第一个设置了KeyBinding的UserControl将Handled设置为true。
  4. TextBox.PreviewTextInput永远不会触发,文本框也不处理输入,因为KeyDown事件设置为已处理。
  5. 这仍然存在问题,如果文本框具有焦点,如何阻止UserControl处理输入?在Command执行中,我可以检查文本框是否具有键盘焦点,但此时已经太晚了。

3 个答案:

答案 0 :(得分:2)

我有同样的问题。 我看了一下key bindind的文档,并且有一个描述,你绑定的键不应该只是键,而是关键的手势,所以它应该是

  • 修改键+普通键
  • 数字键盘键
  • 功能键。

当然,它只适用于A,但总的来说这是不好的做法。您应该考虑实施一些后面提到的可能性。更多https://msdn.microsoft.com/cs-cz/library/system.windows.input.keybinding(v=vs.110).aspx

答案 1 :(得分:0)

TextInputPreviewTextInput仅在文本实际更改/可能更改时触发。

当您更新要反映的问题时,Command会拦截事件,并且永远不会引发(预览)TextInput事件。

最好的解决方案是为你的KeyBinding添加一个修饰键,但我怀疑这不是你喜欢的方式。

另一个选项是e.Handle TextBox上的PreviewKeyDown事件,并使用类似的东西自己引发TextComposition事件:

target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, 
new TextComposition(InputManager.Current, target, "A")) 
{ 
    RoutedEvent = TextCompositionManager.TextInputEvent 
});

(或者,在正确的textBox.Text

中插入CaretIndex

说实话,它仍然是一个黑客。

答案 2 :(得分:-1)

只要您使用KeyBinding,就不会在没有重大黑客攻击的情况下起作用。为此,我实现了一个解决方案:

  1. 使用KeyDown事件捕获被按下的键(而不是KeyBindings)。这将在代码的后面,然后从那里打开按下的键以调用所需的命令(在您的情况下为SomeCommand)。
  2. 现在您遇到了另一个问题。 TextBox正在获取输入,但是您的键绑定命令也在触发。在后面的代码中,检查keyEventArgs.InputSource的类型,如果它是TextBox,则忽略按键。

它应该像这样:

private void OnKeyDown(object sender, KeyEventArgs e)
{
    ICommand command = null;

    switch (e.Key)
    {
        case Key.A:
            command = Commands.SomeCommand;
            break;
        case Key.B:
            command = Commands.SomeOtherCommand;
            break;
    }

    bool isSourceATextBox = e.InputSource.GetType() == typeof(TextBox);
    if (command != null && !isSourceATextBox)
    {
        command.Execute(parameter:null);
    }
}