【実務・中級編】VB.NETでのイベント駆動プログラミング入門:AddHandlerとHandlesキーワードの使い分け – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

VB.NETのイベント駆動を掌握せよ:HandlesとAddHandlerの「正しい境界線」とメモリリークの殲滅

業務自動化ツールを開発していると、必ず突き当たる壁がある。「動的に生成したコントロールのイベントをどう制御するか」だ。

「とりあえずデザイナーでポチポチ配置して`Handles`で書く」のは入門レベルで卒業すべきだ。プロフェッショナルなツール開発者は、実行時に動的にUIを生成し、不要になった瞬間にメモリをクリーンに解放する。

今日は、Visual Basicにおけるイベント配線の極意と、現場で「動かない」「重い」と言わせないための堅牢な実装テクニックを伝授する。

1. 静的(Handles) vs 動的(AddHandler):使い分けの鉄則

VB.NETにおけるイベント購読には2つのアプローチがある。

Handles(静的購読)

デザイナーで配置したコントロールに対し、コンパイル時にイベントを紐付ける方法。

  • メリット: 記述が簡潔で、VB特有の読みやすさがある。
  • デメリット: 実行時に生成されるコントロールには使えない。

AddHandler(動的購読)

プログラム実行中に、動的にイベントハンドラを登録する方法。

  • メリット: コントロールの増減が自由自在。
  • デメリット: 解除(RemoveHandler)を忘れると、一生ガベージコレクション(GC)されない(メモリリークの温床)。

結論: 固定的なUIは`Handles`で良いが、リストやグリッド、動的生成フォームには必ず`AddHandler`を採用せよ。

2. 実践:動的生成とメモリリークを防ぐコード

例えば、ボタンを動的に生成し、クリック時にデータベースと連携してログを吐くツールを作る場面を想定しよう。最も重要なのは、「購読したら必ず解除する」というライフサイクル管理だ。

.net
Public Class DynamicManager
‘ 動的に生成したコントロールを管理するリスト
Private WithEvents _dynamicButtons As New List(Of Button)

Public Sub CreateButton(ByVal id As Integer)
Dim btn As New Button With {
.Name = “Btn_” & id,
.Text = “実行 ” & id
}

‘ 【重要】イベントの購読
AddHandler btn.Click, AddressOf DynamicButton_Click

Me.Controls.Add(btn)
End Sub

Private Sub DynamicButton_Click(sender As Object, e As EventArgs)
‘ senderをキャストして動的に生成されたボタンを特定する
Dim btn = DirectCast(sender, Button)

‘ DB連携処理などをここに記述
‘ 例: LogService.Write(btn.Name & ” が押されました”)
End Sub

‘ 【極めて重要】フォーム破棄時に必ずイベントを解除する
Protected Overrides Sub Dispose(disposing As Boolean)
If disposing Then
‘ コントロールのループを回してRemoveHandlerを実行
For Each ctrl In Me.Controls.OfType(Of Button)()
RemoveHandler ctrl.Click, AddressOf DynamicButton_Click
Next
End If
MyBase.Dispose(disposing)
End Sub
End Class

3. なぜ「RemoveHandler」を怠ってはいけないのか

多くの開発者が陥るのが、「Disposeやフォームを閉じればメモリは解放されるだろう」という甘い考えだ。

イベントを購読するということは、「イベント発生元(Publisher)が購読者(Subscriber)への参照を保持し続ける」ことを意味する。もし購読側がDisposeされても、イベント元が生きている限り、GCはメモリを回収できない。これが「ツールを使い続けると徐々に重くなる」現象の正体だ。

特に、データベース接続オブジェクトや大容量のDataTableを保持したクラスでこれをやると、あっという間にメモリ不足(OutOfMemoryException)を招く。

4. 堅牢な設計のための3つの指針

1. 「ID」で管理せよ: コントロール名(Nameプロパティ)を「Btn_101」のように規則性を持たせて運用する。`sender`から取得したNameを解析すれば、どのデータと紐付いているか即座に特定できる。
2. イベントハンドラは最小限に: すべてのボタンに個別のメソッドを割り当てるのはナンセンスだ。上記コードのように、共通のイベントハンドラ内で`sender`をキャストして処理を分岐させるのが、保守性の高いコードの書き方である。
3. 例外処理を忘れない: ファイル操作やDB連携をイベントハンドラ内に記述する場合、必ず`Try-Catch-Finally`で囲むこと。UIスレッドでの予期せぬクラッシュは、業務ツールとしては致命的だ。

最後に:エンジニアとしての矜持

コードを書くことは、単に動くものを作ることではない。「後から見た誰かが、あるいは未来の自分が、一切の不安なくコードを修正できる状態」を維持することだ。

`AddHandler`を使いこなすということは、プログラムの「生と死(ライフサイクル)」を掌握するということ。この感覚を身につければ、君が作る業務自動化ツールは、どんなに複雑になっても決して崩れることはない。

さあ、エディタを開いて、君のコードに魂を吹き込め。

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