Validating と Varidated の使い方 への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 TOMTOM  (社会人) 投稿日時 2009/4/22 03:06:07
刈谷勇さん、はじめまして。

そうですね。VBには便利なデバッグ機能があるのでした。
不具合が起きると、実行して出た結果から推測して修正するクセがなかなか抜けません^^;
改めてデバッグ機能でどういう動きになるのか見てみたところ
Validated内が実行されていない訳ではなく、既に次へフォーカスが移ってしまっていたのですね。
Validatedイベントはフォーカスが外れていく時に起きるイベントと認識していたもので、
まさかフォーカスが移動してしまってからValidatedイベントが起きてるとは予想もしていませんでした。

今回のようにmsgboxを出す場合と出さない場合でフォーカスの取得結果が変わるというのが
講座の中でクセがあると言われていた部分なのでしょうか。
講座の中で提示されているどのパターンとも違うようですし、まだ他にも状況によって変わるのかもしれませんね。

刈谷勇さんにご提示頂いたコードを見て、なぜここでsenderが出てくるのだろう?と
不思議に思いながらローカルウィンドウとにらめっこしてみましたが
実はsenderには沢山の情報が詰まっていたのですね。
こういうコントロール名の取得方法もあるとは面白いです。
他にもいろいろ出来そうですね。

非常に勉強になりました。
ありがとうございました。

また分からない事が出てきたら、その時はお手間を取らせて恐縮ですが宜しくお願い致します。
投稿者 刈谷勇  (社会人) 投稿日時 2009/4/21 18:56:26
はじめまして、TOMTOMさん。
私も、学生時代と社会人になりたてのころにCOBOLをやっていました。
(もう、すっかり忘れていますが・・・)

で、ご質問のほうですが、原因としてはValidatingやValidated内でSetFocusプロパティを使っているのが原因です。
Validatingでは、Validatingイベントが発生したオブジェクト(ここではtxtSyuksu)にあるのですが、Validatedでは、移動先のオブジェクトにフォーカスが移っています。

この場合、以下のようにすれば問題ないと思います。

'i = Syuksu_Focus() '現在フォーカスのあるtxtSyuksu?の位置を取得  
Dim Name As String
Name = DirectCast(sender, TextBox).Name
i = Name.Substring(Name.Length - 1)


また、VBはCOBOLと違っていろいろデバッグ機能がありますので、ここの初級講座の「第5章 開発作業とデバッグ」を見ていただければとおもいます
投稿者 TOMTOM  (社会人) 投稿日時 2009/4/21 05:35:33
はじめまして。
今までずっとCOBOLを使っていたのですが、VBを独学で覚えなければならなくなり
VBは全く触ったことが無かった為、途方にくれていたところ
こちらのサイトにたどり着きまして、こちらの講座には大変お世話になっております。
いくつか入門用のサイトを巡ってきましたが、私のような者にはこちらの講座は
非常に分かりやすくて助かっています。

今回投稿させていただいたのは、VaridatingとVaridatedについて不可解な現象に遭遇した為
なぜこういう動きになるのか、どこが悪いのかご指摘いただければと思った次第です。

やりたい事は、まずPanel1が有りまして、その中にtxtHatsu1~9、txtSyuksu1~9、txtGtanka1~9、
txtGkin1~9のテキストボックスが有ります。
あらかじめデータを読み込んで、数値をテキストボックスに表示しておきます。
そこでtxtSyuksu?の中の数値を変更してフォーカスを次に移動する時に
txtHatsu?の中の数値と比較して、txtHatsu?よりtxtSyuksu?の方が小さければ
txtSyuksu?とtxtGtanka?を掛算した結果をtxtGkin?へ表示。
逆にtxtHatsu?よりtxtSyuksu?の方が大きければ確認のmsgboxを出して、
”はい”を選択すると同様に計算し、”いいえ”を選択すると計算せずにフォーカス移動もキャンセルという動きにしたいのです。

そこで以下のようなコードを書いたのですが、起きている現象は
txtHatsu?よりtxtSyuksu?の方が大きければ確認のmsgboxが出るところまでは良いのですが、
”はい”を選択してもフォーカスは移動するのですが計算がされません。
msgboxが出るのでVaridatingイベントは起きているでしょうし、
txtHatsu?よりtxtSyuksu?の方が小さければ計算されるのでVaridatedイベントも起きていると思うのですが
何故こうなってしまうのでしょう?
Varidatedイベント発生時の内容をVaridatingイベント発生時の処理の後ろに挿入してやると
とりあえずやりたい内容は出来るのですが、私の書き方が根本的に間違っているのか、
或いはもしかしてVaridatingとVaridatedを両方書くというのは本来やるべきでない方法なのでしょうか?

ちなみにMicrosoft Visual Basic 2008 Express Editionを使っています。

    Private Sub txtSyuksu_Validated(ByVal sender As ObjectByVal e As System.EventArgs) Handles txtSyuksu1.Validated, txtSyuksu2.Validated, txtSyuksu3.Validated, txtSyuksu4.Validated, txtSyuksu5.Validated, txtSyuksu6.Validated, txtSyuksu7.Validated, txtSyuksu8.Validated, txtSyuksu9.Validated
        Dim kingaku As Decimal
        Dim i As Integer

        i = Syuksu_Focus() '現在フォーカスのあるtxtSyuksu?の位置を取得 

        If Panel1.Controls("txtSyuksu" & i).Text = "" Or Panel1.Controls("txtGtanka" & i).Text = "" Then
            Exit Sub
        End If

        kingaku = CDec(Panel1.Controls("txtSyuksu" & i).Text) * CDec(Panel1.Controls("txtGtanka" & i).Text)
        Panel1.Controls("txtGkin" & i).Text = kingaku

    End Sub

    Private Sub txtSyuksu_Validating(ByVal sender As ObjectByVal e As System.ComponentModel.CancelEventArgs) Handles txtSyuksu1.Validating, txtSyuksu2.Validating, txtSyuksu3.Validating, txtSyuksu4.Validating, txtSyuksu5.Validating, txtSyuksu6.Validating, txtSyuksu7.Validating, txtSyuksu8.Validating, txtSyuksu9.Validating
        Dim i As Integer
        Dim wkHatsu As Decimal
        Dim wkSyuksu As Decimal
        Dim RET As Integer

        i = Syuksu_Focus() '現在フォーカスのあるtxtSyuksu?の位置を取得 

        If Panel1.Controls("txtHatsu" & i).Text = "" Or Panel1.Controls("txtSyuksu" & i).Text = "" Then
            Exit Sub
        End If

        wkHatsu = CDec(Panel1.Controls("txtHatsu" & i).Text)
        wkSyuksu = CDec(Panel1.Controls("txtsyuksu" & i).Text)
        If wkHatsu < wkSyuksu Then
            RET = MsgBox("発注数より多いのですか?", MsgBoxStyle.YesNo + MsgBoxStyle.Question, "確認")
            If RET = vbNo Then
                e.Cancel = True
            End If
        End If

    End Sub

    Private Function Syuksu_Focus() As Integer
        Dim i As Integer = 1

        Select Case True
            Case txtSyuksu1.Focused = True
                i = 1
            Case txtSyuksu2.Focused = True
                i = 2
            Case txtSyuksu3.Focused = True
                i = 3
            Case txtSyuksu4.Focused = True
                i = 4
            Case txtSyuksu5.Focused = True
                i = 5
            Case txtSyuksu6.Focused = True
                i = 6
            Case txtSyuksu7.Focused = True
                i = 7
            Case txtSyuksu8.Focused = True
                i = 8
            Case txtSyuksu9.Focused = True
                i = 9
        End Select

        Return i

    End Function