【実務・中級編】フォームの「ActiveControl」プロパティで実現する、汎用的な入力バリデーション関数 – Access VBA解析バイブル

スポンサーリンク

フォームのバリデーションを「個別記述」する時代は終わった:ActiveControlで実現する疎結合な設計術

Access開発の現場で、まだ「各コントロールの『更新後処理(AfterUpdate)』にひたすらIF文を書き連ねている」なら、今すぐその手を止めてほしい。

数百のコントロールを持つフォームで、仕様変更のたびに全てのイベントハンドラを修正する……それは「設計」ではなく「作業」だ。バグの温床を自ら育てていることに他ならない。

今回は、Accessの`Screen.ActiveControl`を核に、バリデーションを「関数」として外部化し、DRY(Don’t Repeat Yourself)原則を極限まで適用する設計手法を伝授する。

なぜ「個別のイベント記述」は滅びるべきなのか

コントロールごとにバリデーションを書くと、以下の「技術的負債」が確実に溜まる。

1. 保守性の欠如: 仕様変更時、フォーム上の全コントロールを巡回して修正する必要がある。
2. ロジックの散逸: 「何をチェックするのか(ビジネスルール)」と「どこでチェックするのか(UIイベント)」が密結合しており、テスタビリティが極めて低い。
3. 属人化: 人によってチェックの書き方がバラバラになり、コードの統一感が失われる。

真のエンジニアは、「イベントはトリガーに過ぎず、ロジックは別個に存在する」という原則に従う。

実装:ActiveControlを用いた汎用バリデーションエンジン

以下のコードを「標準モジュール(例: `modValidator`)」に記述してほしい。フォーム側からは、この関数を呼び出すだけの「薄いラッパー」として機能させる。

1. 標準モジュール (modValidator)

Option Compare Database
Option Explicit

‘ バリデーションの型定義(Enumで管理すると保守性が向上する)
Public Enum ValidateType
vtRequired = 1 ‘ 必須チェック
vtNumeric = 2 ‘ 数値チェック
End Enum

‘ 汎用バリデーション関数
‘ @param ctrl: 検査対象のコントロール
‘ @param vType: 検査ルール
Public Function ValidateControl(ctrl As Control, vType As ValidateType) As Boolean
Dim isValid As Boolean: isValid = True

Select Case vType
Case vtRequired
If IsNull(ctrl.Value) Or ctrl.Value = “” Then isValid = False
Case vtNumeric
If Not IsNumeric(ctrl.Value) Then isValid = False
End Select

‘ 不正な場合のUIフィードバック
If Not isValid Then
MsgBox ctrl.Name & ” に不正な値が入力されています。”, vbCritical, “バリデーションエラー”
ctrl.SetFocus
End If

ValidateControl = isValid
End Function

2. フォーム側の実装(極限までシンプルに)

各コントロールの`BeforeUpdate`イベントには、以下の一行を書くだけだ。

Private Sub txtUserName_BeforeUpdate(Cancel As Integer)
‘ 必須チェックの適用
If Not ValidateControl(Screen.ActiveControl, vtRequired) Then
Cancel = True ‘ 入力をキャンセルしてフォーカスを留める
End If
End Sub

アーキテクトの視点:この設計の「強み」と「注意点」

なぜ `Screen.ActiveControl` なのか

`Screen.ActiveControl`は、現在フォーカスがあるオブジェクトを動的に取得する。これにより、どのコントロールから呼ばれても関数側は「自分を呼び出した相手」を特定できる。これが、汎用関数を作る上での強力な武器となる。

堅牢性を高めるための「3つの鉄則」

1. Cancel = True を忘れない: `BeforeUpdate`でバリデーションを行う際、`Cancel = True`をセットしなければ、不正な値がバッファからテーブルへ書き込まれてしまう。ここが最大のバグポイントだ。
2. エラーハンドリングの徹底: 万が一、関数内でエラーが発生した場合、フォームの入力が止まったままになる可能性がある。運用環境では必ず`On Error GoTo`で例外処理を組み込むこと。
3. DB連携との分離: バリデーション関数内で`CurrentDb.Execute`などを実行してはいけない。バリデーションは「純粋なUIチェック」に徹し、データの整合性チェック(重複確認など)は別途サービスクラスを設けて分離させるのがプロの作法だ。

最後に:コードは「資産」であるべき

あなたの書くVBAコードは、使い捨てのスクリプトではない。将来、別のプロジェクトや、より大規模なシステムに移植されてもなお輝く「資産」であるべきだ。

今回紹介した「ActiveControlを用いたバリデーションの共通化」は、その第一歩だ。まずは既存のフォームのコードを削ぎ落とし、この設計に置き換えてみてほしい。開発効率が劇的に向上し、何より「バグを探す時間」から解放されるはずだ。

次は、これをさらに進化させ、コントロールの「タグ(Tag)」プロパティを活用して、コードすら書かずにバリデーションを自動適用する方法を解説してもいい。準備ができたら、またここへ戻ってくるといい。

タイトルとURLをコピーしました