代码之家  ›  专栏  ›  技术社区  ›  Will

如何防止输入控件从TextCompositionManager中窃取空格字符?

  •  4
  • Will  · 技术社区  · 15 年前

    相关(但不是重复!)关于这个问题: Help with the WPF TextCompositionManager events

    当使用 文本合成管理器 我有一个问题,如果一个输入控件(如文本框)有焦点,文本框将在我有机会对其执行操作之前“窃取”空格字符。

    例如,我们有以下代码:

    public Window1()
    {
      TextCompositionManager.AddPreviewTextInputStartHandler
        (this, PreviewTextInputStartHandler);
    }
    
    private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
    {
      CaptureTextBlock.Text += e.Text;
      e.Handled = true;
    }
    

    窗口1的外观如下:

    <!--standard window crap above here-->
    <StackPanel>
      <TextBlock Name="CaptureTextBlock" />
      <TextBox Name="ThievingBastard" />
    </StackPanel>
    <!-- snip -->
    

    现在,如果运行此应用程序并立即键入“I haet thieving bascards”,则文本块将包含文本“I haet thieving bascards”,文本框将为空。

    但是,如果我聚焦文本框(即,文本框具有键盘焦点),在输入上述行后,文本块将包含文本“iHaetthivingBastards”,文本框将包含文本“”(3个空格)。


    我有两个问题:
    1)我是否可以仅使用TextCompositionManager提供的设施来防止这种情况发生?
    2)如果没有,我应该在哪里插入文本输入堆栈,以便我可以 在我的WPF应用程序中控制文本输入(即使考虑P/Invoking也有负面影响)(您只是考虑过,添加了负面影响)?


    更新

    我使用的是一个黑客解决方案,在这里我只为空间处理inputmanager中的隧道keydown事件。这种方法很笨拙,效率很低,而且基本上很臭。仍在寻找更好的方法。

    1 回复  |  直到 12 年前
        1
  •  6
  •   Will    15 年前

    为了其他人的利益,我的黑客代码。

    我的应用程序正在等待读卡器刷卡。以下内容存在于监视刷卡的对象的构造函数中(这是一个附加项目;大多数注释光标都被编辑掉了):

    // this is where we handle the space and other keys wpf f*s up.
    System.Windows.Input.InputManager.Current.PreNotifyInput += 
        new NotifyInputEventHandler(PreNotifyInput);
    // This is where we handle all the rest of the keys
    TextCompositionManager.AddPreviewTextInputStartHandler(
        Application.Current.MainWindow, 
        PreviewTextInputHandler);
    

    两种方法:

    /// <summary>
    /// Handles the PreNotifyInput event of the input manager.
    /// </summary>
    /// <remarks>Because some controls steal away space (and other) characters, 
    /// we need to intercept the space and record it when capturing.</remarks>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The 
    /// <see cref="System.Windows.Input.NotifyInputEventArgs"/> 
    /// instance containing the event data.</param>
    private void PreNotifyInput(object sender, NotifyInputEventArgs e)
    {
        // I'm only interested in key down events
        if (e.StagingItem.Input.RoutedEvent != Keyboard.KeyDownEvent)
            return;
        var args = e.StagingItem.Input as KeyEventArgs;
        // I only care about the space key being pressed
        // you might have to check for other characters
        if (args == null || args.Key != Key.Space)
            return;
        // stop event processing here
        args.Handled = true;
        // this is my internal method for handling a keystroke
        HanleKeystroke(" ");
    }
    
    
    /// <summary>
    /// This method passes the event to the HandleKeystroke event and turns
    /// off tunneling depending on whether or not Capturing is true.
    /// Also calls StopCapturing when appropriate.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The 
    /// <see cref="System.Windows.Input.TextCompositionEventArgs"/> 
    /// instance containing the event data.</param>
    private void PreviewTextInputHandler(object sender, 
        TextCompositionEventArgs e)
    {
        HanleKeystroke(e.Text);
    }
    

    当有人按下一个键(或向系统发送一个击键)时,会触发PrenotifyInput事件。在这种情况下,我决定它是否是一把特殊的钥匙(对我来说,我必须担心空间,但其他钥匙显然需要特别注意)。如果它是一个特殊的键,我将“处理”该事件,停止对该击键的所有进一步处理。然后我调用在空间中传递的内部处理方法(或者我刚刚截获的任何特殊键)。

    所有其他键都由previewtextinputhandler方法处理。

    这段代码中有很多东西被去掉了。确定刷卡事件发生的时间、确定刷卡完成的时间、安全措施(如果我从未停止捕获刷卡,则超时)等都将被删除。您如何做这些事情将取决于您的代码需求。