none
[VB2005] TextboxのValidatingイベントによるTabControlの移動制御 RRS feed

  • 質問

  • VB2005でWindowsフォームのアプリケーションを開発しています。

    複数のTabPageを持つTabControl内にそれぞれTextboxとButtonが配置してあり、
    Textbox.Validatingイベントでは、入力値のチェックを行っております。
    チェックの結果、入力値が異常であれば、エラーメッセージを表示し、
    e.Cancel=Trueによって移動しないようにしています。

    上記のような状態で、Tabを切り替える動作を行うと、エラーメッセージの表示と移動のキャンセルは行われるのですが、
    それ以降、TabPage内のButton.Clickイベントが発生しなくなってしまいます。
    正常な値を入力して別のTabに切り替えて戻ってくると、Button.Clickイベントが正しく発生するようになりました。

    シンプルにe.Cancel=Trueで移動を制御するのは無理なのでしょうか。

    2009年9月1日 11:43

回答

  • この例ですと、 e.Cancel = True の後に、MessageBox.Show("TextBox1 validating") などとメッセージボックス(またはモーダルダイアログ)を表示した場合など、質問者さんの現象が再現しないでしょうか?
    2009年9月3日 8:36
  • この例ですと、 e.Cancel = True の後に、MessageBox.Show("TextBox1 validating") などとメッセージボックス(またはモーダルダイアログ)を表示した場合など、質問者さんの現象が再現しないでしょうか?
     ↑なるほど、こうすると再現しました。(言語は VS2008 Express の C# で試しました。)
    ところが、画面とコードをいじってから、元に戻す作業(後から追加したコントロール削除とコードのコメント化)を
    おこなったら、また再現しなくなりました。(なぜだろう。。)

    ともかく aodus様とおなじと思われる現象を確認することはできましたが
    現象が出にくいという点では異なるようです。
    この現象の違いが環境の問題といわれれば、そうかもしれません。
    .NET のバージョンでいうと、.NET Framework 3.5 SP1 がインストールされています。

    ちなみにコードをどういじってみたかというと
    下記コードのとおり else 側でもメッセージ表示してみました。
    これだと、ボタンをクリックしたときに else 側を通った場合、
    フォーカスはボタンに移りますがボタンのクリックイベントは実行されませんでした。
    こうしてみると Validating 自体の実装には大変な苦労があるんだろうなと思いました(v v)
            private void textBox1_Validating(object sender, CancelEventArgs e)
            {
                if (textBox1.Text == string.Empty)
                {
                    e.Cancel = true;
                    MessageBox.Show("TextBox1 validating");
                }
                else
                {
                    MessageBox.Show("TextBox1 else");
                }
            }
    以上、とりあえずご報告&etc.でした。
    2009年9月3日 12:24
  • VS2008(C#)で確認したところ、現象が再現できました。
    (元々確認していた環境はVS2005(VB)でした。)

    1.TabControl上に配置されたControlのValidatingイベントで、以下の処理を行う。
      (1)Cancel=Trueとする
      (2)MessageBoxなどのモーダルダイアログを表示する。

    2.配置したControlにフォーカスがある状態で、TabPageを切り替える。
      →ControlのValidatingイベントが発生する。
        ダイアログが表示される。TabPageは替わらない。

    3.この後、ControlのValidatingでCancel=Trueとならないようにする。
      (今回の例ではTextBoxに何か入力する)

      ValidatingでCancelされないのでButtonをクリックできるが、イベントは発生されない。
      尚、Form上にComboBoxが配置されている場合、ドロップダウンの▼をマウスクリックすると、
      一瞬リストが表示されるが、すぐに閉じてしまいます。
    2009年9月3日 15:57
  • 1.TabControl上に配置されたControlのValidatingイベントで、以下の処理を行う。
      (1)Cancel=Trueとする
      (2)MessageBoxなどのモーダルダイアログを表示する。

    2.配置したControlにフォーカスがある状態で、TabPageを切り替える。
      →ControlのValidatingイベントが発生する。
        ダイアログが表示される。TabPageは替わらない。

    3.この後、ControlのValidatingでCancel=Trueとならないようにする。
      (今回の例ではTextBoxに何か入力する)

      ValidatingでCancelされないのでButtonをクリックできるが、イベントは発生されない。
    ↑この手順で繰り返し再現することが確認できました。

    マウスダウン、アップイベントは起きるので回避策はとれそうですが…。
    2009年9月4日 4:13
  • 細かいバージョンは分かりませんが、.NET FW 3.5 SP1が入っているPCでも、
    入っていないPC(.NET FW 2.0まで)でも、手元の環境では今の所100%再現しています。
    根本的な原因は分かりませんが、以下の処理でその場凌ぎはできそうなので何とかしてみます。

    (1)Textbox.Validating発生時チェックがパスできない時、以下a,bの分岐を行う
    (1.a)ActiveControlがTabControlで無い場合はe.Cancel=True、
    (1.b)ActiveControlがTabControlである場合はe.Cancel=Trueを行わず、
           フォーカスをsenderに合わせてTab移動不可フラグをTrue、
    (2)TabContorl.Deselecting発生時にTab移動不可フラグがTrueならe.Cancel=True


    相談に乗っていただき、誠にありがとうございました。

    2009年9月5日 11:04
  • まず、Enter や Leave など、フォーカス移動中に発生するイベント ハンドラで Debug.WriteLine を使ってメッセージを出し、フォーカス移動が完了するまでに発生するイベントを把握してください。そして、フォーカス移動が完了するまで、他のコントロールにフォーカスを移さないようにしてください。入力エラーの通知には、ErrorProvider を使いましょう。


    ずっと以前に、そういう回答をした、かすかな記憶がある...


    Jitta@わんくま同盟
    2009年9月7日 21:24

すべての返信

  • (C# でですが)試してみました。
    でも再現しません。

    Button をマウスクリックする前に
    Textbox 内の入力値はエラー値から正常値に変えてますよね?
    2009年9月2日 11:37
  • 以前にマイクロソフトのテクニカルサポートに問い合わせた事があります。
    可能であれば一度問い合わせてみられてはいかがでしょうか。
    2009年9月3日 0:19
  • (C# でですが)試してみました。
    でも再現しません。

    Button をマウスクリックする前に
    Textbox 内の入力値はエラー値から正常値に変えてますよね?
    C#の開発環境を所持していないので、VC#2008Expressで試してみましたが、同じ挙動になりました。
    会社(VB2005)と自宅(VB2008Express,VC#2008Express)で発生しているのでPC固有の問題ではないと思います。

    エラー値のままだと、Button.Clickの前にTextbox.Validatingが発生しますので、
    Textbox内の入力値を正常値に変えてからButtonをマウスクリックしています。

    2009年9月3日 4:28
  • エラー値のままだと、Button.Clickの前にTextbox.Validatingが発生しますので、
    Textbox内の入力値を正常値に変えてからButtonをマウスクリックしています。

    承知いたしました。

    VB2005 でも試してみたのですが再現しませんでした。。
    以下、試した内容です。再現しなかったのであれですが御参考まで。。

    プロジェクトを新規作成。
    タブコントロールの各タブにテキストボックス、ボタンを配置。
    コードは後述のとおりです。

    テストの実行手順は、、、
    実行 → TabPage1 のテキストボックスをクリック
    → TabPage2 のラベルをクリック(タブ移動がキャンセルされます。)
    → テキストボックスに文字入力 → Button1 をマウスクリック(メッセージが表示されます。)

    以上の正常動作を確認しました。

    Public Class Form1

        Private Sub TextBox1_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
            If TextBox1.Text = "" Then
                e.Cancel = True
            End If
        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            MessageBox.Show("a click")
        End Sub

        Private Sub TextBox2_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox2.Validating
            If TextBox2.Text = "" Then
                e.Cancel = True
            End If
        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            MessageBox.Show("b click")
        End Sub
    End Class

    2009年9月3日 5:37
  • この例ですと、 e.Cancel = True の後に、MessageBox.Show("TextBox1 validating") などとメッセージボックス(またはモーダルダイアログ)を表示した場合など、質問者さんの現象が再現しないでしょうか?
    2009年9月3日 8:36
  • この例ですと、 e.Cancel = True の後に、MessageBox.Show("TextBox1 validating") などとメッセージボックス(またはモーダルダイアログ)を表示した場合など、質問者さんの現象が再現しないでしょうか?
    kanepom さん
    Textbox.Validatingでのエラーメッセージ表示を削除してみましたが、
    相変わらずButton.Clickが発生しない状況が続いています。


    あんにんご さん
    VB2008Expressですが、
    プロジェクト作成、フォームにTabControl配置、TabPageそれぞれにTextboxとButtonを配置、
    既存のコードを全て削除して、あんにんご さんのコードをPublic Class~End Classまで貼り付け。
    実行→Textbox(TabPage1)マウスクリック→TabPage2マウスクリック<Validatingにより移動せず
    →Button(TabPage1)マウスクリック<何も表示されず
    となりました。

    まったく同じコードで動作が異なると言うのは、環境の問題と捕らえるのが無難かと思い始めました・・・。
    2009年9月3日 10:48
  • この例ですと、 e.Cancel = True の後に、MessageBox.Show("TextBox1 validating") などとメッセージボックス(またはモーダルダイアログ)を表示した場合など、質問者さんの現象が再現しないでしょうか?
     ↑なるほど、こうすると再現しました。(言語は VS2008 Express の C# で試しました。)
    ところが、画面とコードをいじってから、元に戻す作業(後から追加したコントロール削除とコードのコメント化)を
    おこなったら、また再現しなくなりました。(なぜだろう。。)

    ともかく aodus様とおなじと思われる現象を確認することはできましたが
    現象が出にくいという点では異なるようです。
    この現象の違いが環境の問題といわれれば、そうかもしれません。
    .NET のバージョンでいうと、.NET Framework 3.5 SP1 がインストールされています。

    ちなみにコードをどういじってみたかというと
    下記コードのとおり else 側でもメッセージ表示してみました。
    これだと、ボタンをクリックしたときに else 側を通った場合、
    フォーカスはボタンに移りますがボタンのクリックイベントは実行されませんでした。
    こうしてみると Validating 自体の実装には大変な苦労があるんだろうなと思いました(v v)
            private void textBox1_Validating(object sender, CancelEventArgs e)
            {
                if (textBox1.Text == string.Empty)
                {
                    e.Cancel = true;
                    MessageBox.Show("TextBox1 validating");
                }
                else
                {
                    MessageBox.Show("TextBox1 else");
                }
            }
    以上、とりあえずご報告&etc.でした。
    2009年9月3日 12:24
  • VS2008(C#)で確認したところ、現象が再現できました。
    (元々確認していた環境はVS2005(VB)でした。)

    1.TabControl上に配置されたControlのValidatingイベントで、以下の処理を行う。
      (1)Cancel=Trueとする
      (2)MessageBoxなどのモーダルダイアログを表示する。

    2.配置したControlにフォーカスがある状態で、TabPageを切り替える。
      →ControlのValidatingイベントが発生する。
        ダイアログが表示される。TabPageは替わらない。

    3.この後、ControlのValidatingでCancel=Trueとならないようにする。
      (今回の例ではTextBoxに何か入力する)

      ValidatingでCancelされないのでButtonをクリックできるが、イベントは発生されない。
      尚、Form上にComboBoxが配置されている場合、ドロップダウンの▼をマウスクリックすると、
      一瞬リストが表示されるが、すぐに閉じてしまいます。
    2009年9月3日 15:57
  • 1.TabControl上に配置されたControlのValidatingイベントで、以下の処理を行う。
      (1)Cancel=Trueとする
      (2)MessageBoxなどのモーダルダイアログを表示する。

    2.配置したControlにフォーカスがある状態で、TabPageを切り替える。
      →ControlのValidatingイベントが発生する。
        ダイアログが表示される。TabPageは替わらない。

    3.この後、ControlのValidatingでCancel=Trueとならないようにする。
      (今回の例ではTextBoxに何か入力する)

      ValidatingでCancelされないのでButtonをクリックできるが、イベントは発生されない。
    ↑この手順で繰り返し再現することが確認できました。

    マウスダウン、アップイベントは起きるので回避策はとれそうですが…。
    2009年9月4日 4:13
  • 細かいバージョンは分かりませんが、.NET FW 3.5 SP1が入っているPCでも、
    入っていないPC(.NET FW 2.0まで)でも、手元の環境では今の所100%再現しています。
    根本的な原因は分かりませんが、以下の処理でその場凌ぎはできそうなので何とかしてみます。

    (1)Textbox.Validating発生時チェックがパスできない時、以下a,bの分岐を行う
    (1.a)ActiveControlがTabControlで無い場合はe.Cancel=True、
    (1.b)ActiveControlがTabControlである場合はe.Cancel=Trueを行わず、
           フォーカスをsenderに合わせてTab移動不可フラグをTrue、
    (2)TabContorl.Deselecting発生時にTab移動不可フラグがTrueならe.Cancel=True


    相談に乗っていただき、誠にありがとうございました。

    2009年9月5日 11:04
  • まず、Enter や Leave など、フォーカス移動中に発生するイベント ハンドラで Debug.WriteLine を使ってメッセージを出し、フォーカス移動が完了するまでに発生するイベントを把握してください。そして、フォーカス移動が完了するまで、他のコントロールにフォーカスを移さないようにしてください。入力エラーの通知には、ErrorProvider を使いましょう。


    ずっと以前に、そういう回答をした、かすかな記憶がある...


    Jitta@わんくま同盟
    2009年9月7日 21:24
  • こんにちは。フォーラムオペレーターの高橋春樹です。

    あんにんごさん、kanepomさん、Jittaさん
    ご投稿ありがとうございました。

    aodusさん、初めまして。
    MSDNフォーラムのご利用ありがとうございます。

    なんとか回避策が見つかってよかったです。
    Validatingイベントハンドラ内の、モーダルダイアログの表示を ErrorProviderを使用して表示させる方法でも回避できるようですね。

    今回、あんにんごさん、kanepomさん、Jittaさんからの投稿が有用なものだと思いましたので、勝手ながら、回答マークを付けさせて頂きました。
    不適切と思いましたら、回答マークを削除することも可能です。

    今後ともMSDNフォーラムをよろしくお願いします(^-^)


    マイクロソフト株式会社 フォーラム オペレーター 高橋春樹
    2009年10月6日 9:15