Windows Formsの「フォーカス迷子」を撲滅せよ:ValidatingとValidatedの極限設計論
業務自動化の現場において、入力値チェックは最も退屈で、かつ最もバグを生み出しやすい領域だ。初心者は往々にしてボタンクリック時に全フィールドのチェックを走らせるような原始的な設計に逃げるが、それではユーザー体験(UX)は向上せず、コードの保守性も崩壊する。
Windows Formsには、古くから存在するが正しく理解されていない「魔法のイベント」がある。それが `Validating` と `Validated` だ。この二つを掌握すれば、UIの整合性は自動化される。今日は、現場で即戦力となる「フォーカス制御の流儀」を授けよう。
—
1. なぜ「ボタンクリック時」のチェックではダメなのか
「保存ボタンを押した瞬間にバリデーションを走らせればいい」。これは一見合理的だが、大規模な業務アプリでは致命的な欠陥となる。
- UXの欠如: ユーザーが10個の項目を入力し終えて初めてエラーを知る。どこを直せばいいか即座に特定できない。
- イベントの競合: `CausesValidation` プロパティの理解不足により、キャンセルボタンを押してもバリデーションが走り、フォームが閉じられなくなる「呪い」が発生する。
我々が目指すべきは、「ユーザーがそのフィールドを去った瞬間に判定を完了させる」という、非同期的なフローだ。
—
2. ValidatingとValidatedの決定的な使い分け
この二つのイベントは、役割が完全に分離されている。
- `Validating` (前処理): 入力値の検証を行い、不正なら `CancelEventArgs.Cancel = True` を投げてフォーカスを固定する。「検問所」である。
- `Validated` (後処理): 検証が成功した後にのみ実行される。データベースへの一時保存や、関連する計算処理など、「正常系」のロジックをここに置く。
してはいけないこと
`Validating` イベントの中で、複雑なデータベース更新や、メッセージボックス(`MessageBox.Show`)を多用してはならない。メッセージボックスはフォーカスを強制的に奪うため、バリデーションループの無限地獄(フォーカスが戻らなくなるバグ)を引き起こす主犯だ。
—
3. 実践:保守性の高いバリデーションパターン
現場でそのまま使える、堅牢な実装例を提示する。ここでは `ErrorProvider` コンポーネントを併用するのが鉄則だ。
”’
”’
Private Sub txtNumericInput_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles txtNumericInput.Validating
Dim txt As TextBox = DirectCast(sender, TextBox)
‘ 1. 空白チェック(任意入力ならここはスキップ)
If String.IsNullOrWhiteSpace(txt.Text) Then
ShowError(txt, “この項目は必須です。”)
e.Cancel = True ‘ フォーカスを離さない
Return
End If
‘ 2. 型チェック(数値変換の可否)
Dim val As Integer
If Not Integer.TryParse(txt.Text, val) Then
ShowError(txt, “数値を入力してください。”)
e.Cancel = True
Return
End If
‘ 3. 正常系:エラー表示をクリアして終了
ErrorProvider1.SetError(txt, “”)
End Sub
”’
”’
Private Sub ShowError(control As Control, message As String)
ErrorProvider1.SetError(control, message)
‘ 必要に応じてビープ音を鳴らす等のUX向上策をここに挿入
End Sub
—
4. プロフェッショナルへのアドバイス:陥りやすい罠
① 「キャンセルボタン」が押せない現象
フォームに「閉じる」や「キャンセル」ボタンを配置する場合、そのボタンの `CausesValidation` プロパティを `False` に設定すること。これを忘れると、入力エラーの状態で「キャンセル」を押しても、バリデーションが邪魔をしてフォームが閉じられなくなる。
② ファイル・DB連携のタイミング
`Validating` の中でDB通信を行ってはならない。なぜなら、ネットワーク遅延が発生した際、UIがフリーズするからだ。検証はあくまで「形式チェック」に留め、DBの存在チェックや整合性チェックは、非同期処理(`Task.Run`)としてバックグラウンドで走らせ、結果をUIに反映させるのが、今の時代の「正解」だ。
③ 責務の分離
バリデーションロジックがフォームのコードビハインドに溢れかえっているなら、それは設計の敗北だ。ロジック部分は別クラス(検証エンジン)に切り出し、フォームからはそれを呼び出すだけの構成にせよ。
—
まとめ:UIを制御する者が、業務を制する
`Validating` イベントを使いこなすことは、ユーザーの「ミス」を「修正可能なステップ」へと昇華させることと同義だ。
コードを書く際は常に、「このイベントが実行される時、ユーザーのフォーカスはどこにあり、何が起きるべきか」を脳内でシミュレートしろ。それができれば、あなたの作る業務ツールは、使いやすく、かつ壊れない「伝説のツール」へと進化するはずだ。
さあ、今すぐ既存のコードの `Click` イベントからバリデーションを剥がし、適切なタイミングへと移設してくるがいい。それが真の自動化エンジニアへの第一歩だ。
