wpf文本框不会引发textInput事件

时间:2019-08-02 20:48:54

标签: wpf routed-events wpf-textbox

我有一个带有文本框的窗口,该窗口在键入时不会引发textInput事件。

我一直在和Snooper一起看它。仅抛出KeyDown和KeyUp事件。

Screenshot of snooper results while typing

IS 响应几个键:空格键,退格键,插入键,起始键,删除键,结束键

它响应复制和粘贴命令以及全选

它不响应任何字符,符号或数字

这是启动程序::此窗口是通过共享方法打开的,该共享方法从代码中的两个不同位置调用。从一个位置调用时,文本框可以完美运行,而从另一位置调用时,则不能。

我已经排除了绑定,数据转换器,样式,控件位置。 我将窗口剥离为一个没有绑定的纯文本框,问题仍然存在。

我已尽我所能来查找此神秘错误。我看不到在甚至未抛出PreviewTextInput之前可能处理我的事件的原因,或者为什么它可能只发生一半的时间。

有关此错误原因的任何想法,或我可以尝试跟踪事件的其他工具,将不胜感激!

编辑:添加一些代码进行演示。该代码已被精简为所需的Barest代码,并且问题仍然存在。

<Window x:Class="EventViewEmail"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="880" Height="600">

    <TextBox VerticalAlignment="Top"/>
</Window>

请注意缺少绑定,样式或其他可能干扰控件的内容

Public Class EventViewEmail
    'all code removed from the view-behind'
End Class   

这是构建窗口的静态类。对此类的两个单独调用以不同的方式构建参数。我已经删除了使用自变量来表明它们不会影响当前问题的代码。

Public Class EventManager
    Public Shared Sub Show(e As EventEdit, p As WorkplanPageViewModel)
        Dim w = New EventViewEmail
        If w Is Nothing Then Return

        'removed datacontext for testing'
        'w.DataContext = e '
        'w.Tag = p'
        w.Show()
    End Sub
End Class

我唯一可以添加的是调用Show()子代码的代码来自两个单独的解决方案。不确定删除所有参数后可能产生的影响

修改2: 我一直试图跟踪事件序列,以缩小处理事件的位置。到目前为止,我可以看到在keyDown和keyUp事件之间,发生了一系列应该 发生的事件,而不是:

  • PreviewInputReport / InputReport(无源)
  • PreviewTextInputStart / TextInputStart(文本框)
  • PreviewTextInput / TextInput(文本框)
  • PreviewInputReport / InputReport(textboxView)

keydown事件没有得到处理,所以我不确定为什么没有触发PreviewInputReport

5 个答案:

答案 0 :(得分:2)

免责声明

我将发布 C#代码,因为我不太熟练 VB 来编写代码(只能在有限的范围内读取)。如果有时间,我会尝试翻译,否则任何人都可以随意翻译。


我已经通过在窗口的可视树上处理PreviewTextInput事件来重现您描述的行为(记住这是隧道路由事件):

<Window (...)>
    <StackPanel>
        <TextBox x:Name="myTextBox"></TextBox>
    </StackPanel>
</Window>
public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        PreviewTextInput += (s, e) => e.Handled = true;
    }
}

因此,我认为这很可能是您造成问题的原因。它还说明the comment to @AQuirky's answer未调用您的PreviewTextInput处理程序。您可以通过不同的订阅来确认是这种情况(即使事件被标记为已处理,也会调用处理程序):

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        PreviewTextInput += (s, e) => e.Handled = true;
        myTextBox.AddHandler(
            routedEvent: PreviewTextInputEvent,
            handler: new TextCompositionEventHandler((s, e) =>
            {
                if (e.Handled)
                    throw new Exception("Gotcha!");
            }),
            handledEventsToo: true);
    }
}

如果这确实是正确的诊断,那么有一件事有些神秘-谁和在哪里处理PreviewTextInput事件?我想这是您要调查的...

This comment from @l33t可能会派上用场:

  

查找诸如EventManager.RegisterClassHandler(typeof(TextBox),UIElement.PreviewTextInputEvent,...)之类的全局事件处理程序和/或行为。您是否正在使用任何第三方UI库?还要查看他们的代码。


更新

由于看来PreviewTextInput毕竟不是罪魁祸首,所以这就是我接下来要做的事情。

如果我没记错的话,会在TextInputEvent之前触发整个事件链,我相信处理这些事件中的任何一个都会破坏链。看起来InputManager负责管理此事件周期(您可以查看其 C#源代码here)。

话虽如此,我建议您进行以下操作:

  1. 使用InputManager.Current订阅其PreProcessInput和/或PostProcessInput事件(还可以选择PreNotifyInputPostNotifyInput
  2. 记录工作场景中的事件链(尤其是检查args的StagingItem.Input.RoutedEvent,该参数包含当前正在处理的路由事件)
  3. 针对无法正常工作的情况重复该过程
  4. 确定第一个差异-在工作场景中正在处理但在不工作场景中未处理的第一个路由事件
  5. 研究上一个常见的路由事件和第一个不同的事件-也许其中一个是在您的代码中处理的?

答案 1 :(得分:0)

问题是,在触发TextInput时(未引发...抛出异常),您没有看到它,因为文本框本身正在使用它。要捕获此事件,您需要使用PreviewTextInput。例如

    <TextBox TextInput="UIElement_OnTextInput" PreviewTextInput="UIElement_OnPreviewTextInput"></TextBox>

具有事件处理程序...

    private void UIElement_OnTextInput(object sender, TextCompositionEventArgs e)
    {
        Console.WriteLine($"In text input event, {e.Text}");
    }

    private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        Console.WriteLine($"In preview text input event, {e.Text}");
    }

从不调用第一个处理程序,始终调用第二个处理程序。

答案 2 :(得分:0)

在这种情况下,事实证明在不工作的情况下启动窗口的表单是winform。 Winform阻止了击键。通过将窗口作为模式打开来解决此问题。

答案 3 :(得分:0)

未调用您的处理程序,因为其他处理程序已将该事件标记为已处理。您可以添加带有AddHandler()的处理程序,并为第三个参数传递true

public MainWindow()
{
    var handler = new RoutedEventHandler(OnTextInput);
    myTextBox.AddHandler(TextInputEvent, handler, handledEventsToo: true);
}

private static void OnTextInput(object sender, RoutedEventArgs e)
{
}

答案 4 :(得分:0)

我在这里遇到了同样的问题。两次调用之间的区别是:一次 WPF-Windows 被称为模态(有效)和一次非模态(不起作用),每次都来自 WindowsForms 窗口。

正如 Shaboboo 在他的回答中所写,这就是区别,但如果您需要调用非模态。 答案是这个thread。 (愚蠢的我,我在 2 年前遇到了同样的问题,问并得到了答案)。我们必须使用

ElementHost.EnableModelessKeyboardInterop(wpfWindow);

再次感谢V.Leon