6

この質問に関連しています(ただし、重複ではありません!): WPFTextCompositionManagerイベントのヘルプ

TextCompositionManagerを使用しているときに、TextBoxなどの入力コントロールにフォーカスがある場合、TextBoxがスペース文字を操作する前に、スペース文字を「盗む」という問題が発生します。

たとえば、次のコードがあります。

public Window1()
{
  TextCompositionManager.AddPreviewTextInputStartHandler
    (this, PreviewTextInputStartHandler);
}

private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
  CaptureTextBlock.Text += e.Text;
  e.Handled = true;
}

Window1は次のようになります。

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

ここで、このアプリケーションを実行してすぐに「I haet thieveing bastards」と入力すると、TextBlockに「Ihaet thieveing bastards」というテキストが含まれ、テキストボックスは空になります。

ただし、テキストボックスにフォーカスを合わせる場合(つまり、テキストボックスにキーボードフォーカスがある場合)、上記の行を入力すると、テキストブロックに「Ihaetthieveingbastards」というテキストが含まれ、テキストボックスに「」(3つのスペース)というテキストが含まれます。


2つの質問があります:
1)TextCompositionManagerによって提供される機能だけでこれが発生するのを防ぐことはできますか?
2)そうでない場合は、テキスト入力スタックにプラグインして、WPFアプリケーション内のテキスト入力を完全に制御できるようにします(p /呼び出しについて考える場合でもマイナスの点)(考えただけでマイナスの点が追加されます) ?


アップデート

私は、スペースに対してのみInputManagerからのトンネリングKeyDownイベントを処理するハッキーな回避策を使用しています。この方法は非常に扱いにくく、非効率的で、基本的に悪臭を放ちます。まだより良い方法を探しています。

4

1 に答える 1

8

他の人の利益のために、私のハッキーなコード。

私の特定のアプリは、カードリーダーからのカードスワイプを待っています。以下は、カードのスワイプを監視するオブジェクトのコンストラクターに存在します(これはサイドプロジェクトです。ほとんどのコメントの冒涜は編集されています)。

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

2つの方法:

/// <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メソッドによって処理されます。

このコードには、多くのものが取り除かれています。スワイプイベントがいつ発生したか、スワイプがいつ完了したか、セーフガード(スワイプのキャプチャを停止しない場合のタイムアウト)などが削除されます。このようなことをどのように行うかは、コード要件によって異なります。

于 2009-10-02T13:37:34.643 に答える