none
TextBoxに半角スペースを入力した際のイベント処理について RRS feed

  • 質問

  • TextBoxで入力文字数をチェックするために、TextInputイベントやTextChangedイベントで処理を行っています。
    概ね目的通りの事が実現できているのですが、唯一半角スペース(IMEがOFFの状態でのスペース・IMEがONの状態でShift+スペース共に)が入力された際にこれらのイベントが発生しません。
    全角スペースは発生する、TextBox.Textプロパティの文字列には入力された半角スペースが含まれているにも関わらず、です。
    現状、スペースのみPreviewKeyDownで処理していますが、これは適切な方法では無いと考えています。
    もし他に良い手段をご存知の方がいらっしゃれば、ご教授いただければと思います。
    2009年6月15日 0:46

回答

  • InputManager.Current.PostProcessInput は半角スペースも取得できます。
    e.StagingItem.Input に情報がきます。

    public Window1()
    {
        InitializeComponent();
        InputManager.Current.PreProcessInput += new PreProcessInputEventHandler(Current_PreProcessInput);
        InputManager.Current.PreNotifyInput += new NotifyInputEventHandler(Current_PreNotifyInput);
        InputManager.Current.PostProcessInput += new ProcessInputEventHandler(Current_ProcessInput);
        InputManager.Current.PostNotifyInput += new NotifyInputEventHandler(Current_NotifyInput);
    }
    
    void Current_PreNotifyInput(object sender, NotifyInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Device.Target == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PreNotifyInput");
        }
    }
    
    void Current_PreProcessInput(object sender, PreProcessInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent)
        {
            if (e.StagingItem.Input.Device.Target == textBox1)
            {
                Debug.WriteLine("InputManager.Current.PreProcessInput");
            }
        }
    }
    
    void Current_ProcessInput(object sender, ProcessInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Source == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PostProcessInput");
        }
    }
    
    void Current_NotifyInput(object sender, NotifyInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Source == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PostNotifyInput");
        }
    }
    


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    • 回答としてマーク みっと 2009年6月19日 8:26
    2009年6月16日 7:28

すべての返信

  • TextChangedイベント は発生します。
    TextBoxを含むどこかのコントロールでイベントを処理済みにしているのかもしれません。
    TextBoxを含む(Window -> Grid -> xxxx -> TextBox の階層的に )コントロールは何を使っていますか?

    以下のプログラムで確認しました。
    なお、TextInputイベントはHELPで「TextBox は複合コントロールであり、その複合内で TextInput イベントは既に処理済としてマークされています。」と書いてありますので発生しません。

    <Window x:Class="TextBoxEvent.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="60" Width="300">
        <Grid>
        <TextBox Name="textBox1" TextChanged="textBox1_TextChanged" />
      </Grid>
    </Window>
    private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
    {
        Debug.WriteLine("textBox1_TextChanged");
    }
    


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年6月15日 17:24
  • To:えムナウさん
    レスありがとうございます。すみません、勘違いしていました。TextChangedは発生しますね。
    (自分でもPreviewTextInputでスペースキーを判断して、TextChangedで処理してたのに何見てたんだろう・・・(苦笑))

    > なお、TextInputイベントはHELPで「TextBox は複合コントロールであり、その複合内で TextInput イベントは既に処理済としてマークされています。」と書いてありますので発生しません。

    すみません、ここも内容が足りませんでした。私が見ていたのは、TextCompositionManagerのTextInputUpdateの方でした。
    ここで新しく入力された文字+既存の文字と最大サイズの比較を行っていたのですが、最初に書いた通りなぜか半角スペース時のみイベントが発生しません。
    TextChangedはIMEの変換でもイベントが発生してしまい使い物になりませんし・・・
    2009年6月16日 0:46
  • TextCompositionManager.TextInputUpdate じゃペーストにも対応できないからどのみち役に立たないと思いますが。
    TextCompositionManager.PreviewTextInputStart から TextCompositionManager.PreviewTextInput まで IME 入力中フラグを立てておき、TextChanged でチェックってのが妥当じゃないですかね。
    // フラグ立てるときに IME による入力中かどうかの判断も必要かな?
    2009年6月16日 2:00
  • 根本に戻ります。
    「入力文字数をチェックする」というのは具体的に何をしたいのでしょうか?
    MaxLength プロパティで解決する問題ではないでしょうか?
    または TextChanged + 正規表現チェック でどうにかならないでしょうか?

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年6月16日 6:30
  • TextChanged は IME 有効での未変換文字入力中も発生するので。MaxLength も同様ですね。
    例えば MaxLength=3 のとき、「集合」を変換経由で入力しようとすると、「しゅう」入れて次に g を打鍵した時点で「しゅう」が確定していまいます。
    TSF 的には正しいかもしんないけどちょっと困る仕様です。
    なもんで、私が一つ前のレスで挙げた未変換文字入力中かどうかってフラグが必要かなーと。
    他にうまい手がありますかね。
    2009年6月16日 6:48
  • MaxLength プロパティにバグがあるのは以下の報告にもあるとおり知っています。
    https://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=332165


    ただ、そのバグを回避することだけが目的なのか聞いているのです。
    それと、TextChanged + 正規表現チェック で回避できないのかも聞きたいところです。
    仕様によってはIMEのフラグチェックも必要かもしれません。

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年6月16日 6:54
  • To:Hongliangさん
    レスありがとうございます。

    > TextCompositionManager.TextInputUpdate じゃペーストにも対応できないからどのみち役に立たないと思いますが。

    はい、それは把握しています。こちらはCommandManagerのPreviewExecutedで同様の処理を行っています。

    > TextCompositionManager.PreviewTextInputStart から TextCompositionManager.PreviewTextInput まで IME 入力中フラグを立てておき、TextChanged でチェックってのが妥当じゃないですかね。

    うーん、やはりそうなりますか。今それに近い構造になってるんですが、あまりにも処理があちらこちらに散らばってしまっていて煩雑すぎるので、もうちょっとマシな方法は無いものかと質問した次第で・・・(苦笑)
    半角スペースでTextCompositionManager.TextInput系のイベントが発生しないのは、個人的には仕様漏れとしか思えないんですけどね。
    (半角スペースはTextじゃないと言われればそれまでですが・・・)
    2009年6月16日 7:03
  • To:えムナウさん
    レスありがとうございます。

    > MaxLength プロパティにバグがあるのは以下の報告にもあるとおり知っています。
    > ただ、そのバグを回避することだけが目的なのか聞いているのです。

    そうです。MaxLengthのバグを回避した上で、最大xバイト(文字数ではなくバイト数)のサイズチェックを行うことが目的です。
    TextChangedで処理を行うと、Hongliangさんもご指摘の通りIMEの変換候補が変わったときにもイベントが発生しますので、
    例えば「やし→香具師」と変換された場合でサイズが5バイトだと、変換された文字で処理がかかってしまうことになります。
    もともとTextCompositionManager.TextInput系のイベントで変換中か変換中でないか・既存文字列+入力文字列がサイズを超えていないかを見て処理していたのですが、
    なぜか半角スペースだけTextCompositionManager.TextInput系イベントが発生しないため、例外的に処理を追加する羽目になり「う~ん」と頭を抱えていた次第です。

    > それと、TextChanged + 正規表現チェック で回避できないのかも聞きたいところです。

    全角・半角が組み合わさるため正規表現ではチェックできず、文字数からバイト数を割り出してのチェックになります。

    2009年6月16日 7:15
  • InputManager.Current.PostProcessInput は半角スペースも取得できます。
    e.StagingItem.Input に情報がきます。

    public Window1()
    {
        InitializeComponent();
        InputManager.Current.PreProcessInput += new PreProcessInputEventHandler(Current_PreProcessInput);
        InputManager.Current.PreNotifyInput += new NotifyInputEventHandler(Current_PreNotifyInput);
        InputManager.Current.PostProcessInput += new ProcessInputEventHandler(Current_ProcessInput);
        InputManager.Current.PostNotifyInput += new NotifyInputEventHandler(Current_NotifyInput);
    }
    
    void Current_PreNotifyInput(object sender, NotifyInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Device.Target == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PreNotifyInput");
        }
    }
    
    void Current_PreProcessInput(object sender, PreProcessInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent)
        {
            if (e.StagingItem.Input.Device.Target == textBox1)
            {
                Debug.WriteLine("InputManager.Current.PreProcessInput");
            }
        }
    }
    
    void Current_ProcessInput(object sender, ProcessInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Source == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PostProcessInput");
        }
    }
    
    void Current_NotifyInput(object sender, NotifyInputEventArgs e)
    {
        if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent &&
            e.StagingItem.Input.Source == textBox1)
        {
            Debug.WriteLine("InputManager.Current.PostNotifyInput");
        }
    }
    


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    • 回答としてマーク みっと 2009年6月19日 8:26
    2009年6月16日 7:28
  • To:えムナウさん
    レスありがとうございました。お返事が遅くなってすみません。
    わざわざソースコードまで提示していただきありがとうございます。先ほど確認しました。確かにこの方法であれば半角スペースの入力も拾えますね。
    参考にさせていただきます。
    色々とありがとうございました。
    2009年6月19日 8:22