【入門編】Windows FormsにおけるBindingSourceとDataTableを用いたマスター・ディテール画面の実装:親子関係のデータ連動をノーコードに近づける設計 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

脱・力技のイベント制御!BindingSourceで実現する「マスター・ディテール」の極意

こんにちは。現場で泥臭いコードと格闘してきたあなたへ。
もしあなたが今、「ヘッダー(請求書)を選んだら、その下の明細が自動で切り替わる」という機能を、ボタン一つ一つにイベントを書いて制御しようとしているなら……今すぐその手を止めてください。

VB.NETの真骨頂は、「データの橋渡し(データバインディング)」をいかにスマートに設計するかにあります。今日は、Windows Formsにおける最強の武器『BindingSource』を使って、コードを極限まで削ぎ落とす設計手法を伝授します。

—

1. なぜ「力技の制御」が破滅を招くのか?

初心者が陥りやすいのが、「ヘッダーのグリッドの行選択イベントで明細を検索し、再読み込みする」という実装です。
これでは、データの整合性が崩れたり、UIとロジックが密結合しすぎてメンテナンス不能な「スパゲッティコード」が完成します。

BindingSourceは、単なるデータの仲介役ではありません。
UIとデータソースの間に立つ「調停者」です。これを使うことで、ヘッダーと明細の同期を「設定」だけで解決できるようになります。

—

2. 準備:データセットの親子関係を定義する

まず、`DataTable`同士に「リレーション(親子関係)」を持たせることがスタートラインです。

.net
‘ 例:請求書ヘッダー(dtHeader)と明細(dtDetail)の準備
Dim ds As New DataSet()
ds.Tables.Add(dtHeader)
ds.Tables.Add(dtDetail)

‘ 請求書ID(InvoiceID)をキーにして親子関係を定義
ds.Relations.Add(“HeaderToDetail”,
ds.Tables(“Header”).Columns(“InvoiceID”),
ds.Tables(“Detail”).Columns(“InvoiceID”))

このリレーションを定義するだけで、VB.NETのエンジンは「どのヘッダーにどの明細が紐づいているか」を理解します。

—

3. 実装の極意:BindingSourceを「二階建て」にする

ここが最大のポイントです。BindingSourceを2つ用意し、明細側のソースをヘッダーのBindingSourceに関連付けます。

.net
‘ ヘッダー用
Dim bsHeader As New BindingSource()
bsHeader.DataSource = ds.Tables(“Header”)

‘ 明細用(これが肝!)
Dim bsDetail As New BindingSource()
‘ データソースをヘッダーのBindingSourceに指定し、リレーション名を渡す
bsDetail.DataSource = bsHeader
bsDetail.DataMember = “HeaderToDetail”

‘ あとはフォームのコントロールにバインドするだけ
txtInvoiceNo.DataBindings.Add(“Text”, bsHeader, “InvoiceNo”)
dgvDetail.DataSource = bsDetail

これだけで完了です。
ヘッダーの行を切り替えると、`bsHeader`の`Position`が変わり、それに連動して`bsDetail`が自動的にフィルタリングされます。あなたはもう、明細を再検索するコードを一行も書く必要はありません。

—

4. 陥りやすい罠と解決策

Q. 「CurrentChanged」で何か処理をしたいときは?

「選択が変わった瞬間に合計金額を再計算したい」といったケースがあるでしょう。その場合は、`bsHeader`の`CurrentChanged`イベントを使います。

.net
Private Sub bsHeader_CurrentChanged(sender As Object, e As EventArgs) Handles bsHeader.CurrentChanged
‘ 現在のヘッダー行が確定した後のタイミングで動く
‘ ここで複雑な計算やログ出力を行うのが、VB.NETらしい設計です
Dim currentHeader As DataRowView = DirectCast(bsHeader.Current, DataRowView)
If currentHeader IsNot Nothing Then
CalculateTotal(currentHeader(“InvoiceID”))
End If
End Sub

Q. データが更新されないときは?

BindingSourceを使っていても、`DataTable`を直接触るとUIが追いつかないことがあります。そんな時は `BindingSource.EndEdit()` を呼んでください。これだけで、編集中の値がデータセットに確定され、即座に同期されます。

—

5. まとめ:エンジニアとして一段階上の視点へ

今回紹介した「BindingSourceによる連動」は、小規模なツールから業務基幹システムまで応用が効く、VB.NETにおける「型」のようなものです。

  • イベントを書きすぎない: BindingSourceに任せられることは任せる。
  • データ構造を正しく作る: DataSet/DataTableのリレーションを疎かにしない。
  • UIを疎結合にする: コントロールとロジックの距離を離す。

ここをクリアすれば、あなたの書くコードは「動く」だけのものから、「保守できる」プロフェッショナルな資産へと変わります。

もし実装で詰まったら、思い出してください。「それはBindingSourceの紐付けで解決できないか?」と。
この問いかけができるようになった時、あなたはもう初心者ではありません。さあ、次の画面設計へ進みましょう!

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