数万件のマスターを瞬時に絞り込む!ComboBoxの「爆速インクリメンタルサーチ」実装術
こんにちは。業務自動化の現場で「なぜかUIが固まる」「検索が遅い」という壁にぶつかったことはありませんか?
VB.NETで数万件の得意先マスターを`ComboBox`に詰め込むと、入力のたびにアプリがフリーズしたような状態になりますよね。それは、「ComboBoxが全てのアイテムをメモリ上で描画しようと必死になっているから」です。
今日は、そんな「重たいUI」を劇的に改善し、数万件のデータでもサクサク動く「仮想化(Virtual Mode)」の考え方と、プロの技術をお伝えします。ここをマスターすれば、あなたのアプリは一気にプロ仕様のレスポンスを手に入れますよ。
—
1. なぜ、標準のComboBoxは遅いのか?
VB.NETの`ComboBox`に数万件のデータを`Items.Add`で追加すると、コントロール内部で数万個のオブジェクトが生成され、Windowsがそれらを管理するために膨大なリソースを消費します。
さらに、ユーザーが1文字打つたびに「一致するデータはあるか?」と全件走査(フルスキャン)を始めれば、UIスレッドは完全にロックされます。「表示」と「検索」を分離する。これが解決の鍵です。
—
2. 爆速化の戦略:キャッシュと動的リスト
数万件のマスターは「メモリ上のリスト(List(Of T))」に置いておき、ComboBoxには「表示に必要な分だけ」を渡す仕組みを作ります。
実装のステップ
1. マスタデータ保持: `List(Of T)`に全データを保持する。
2. 高速検索: `LINQ`を使って、入力文字に一致する件数だけを抽出する。
3. UIの更新: ComboBoxの`DataSource`を、抽出したリストに入れ替える。
—
3. 実装コード:プロのインクリメンタルサーチ
それでは、実際にコードを見ていきましょう。この手法なら、数万件あっても0.1秒以下で絞り込みが完了します。
.net
Imports System.Collections.Generic
Imports System.Linq
Public Class MainForm
‘ 全データを保持するマスターリスト
Private masterList As List(Of Customer) = New List(Of Customer)()
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ ダミーデータの生成(実際はデータベースからロード)
For i As Integer = 1 To 50000
masterList.Add(New Customer With {.ID = i, .Name = “得意先_” & i})
Next
End Sub
‘ ComboBoxのテキストが変わるたびに呼び出す
Private Sub cmbSearch_TextChanged(sender As Object, e As EventArgs) Handles cmbSearch.TextChanged
Dim keyword As String = cmbSearch.Text
‘ 3文字以上入力されたら絞り込みを開始(負荷軽減のコツ)
If keyword.Length < 3 Then Return
' LINQで高速フィルタリング
' .Take(100) を入れることで、描画する最大件数を制限し、メモリ負荷を抑える
Dim filteredList = masterList.Where(Function(c) c.Name.Contains(keyword)).Take(100).ToList()
' DataSourceの更新
cmbSearch.DataSource = filteredList
cmbSearch.DisplayMember = "Name"
' ドロップダウンを自動的に開く
If Not cmbSearch.DroppedDown Then cmbSearch.DroppedDown = True
End Sub
End Class
' 得意先クラス
Public Class Customer
Public Property ID As Integer
Public Property Name As String
End Class
コードの解説
- `.Where(…).Take(100)`: ここが肝です。数万件中から全件探すと遅いので、まずは`Where`で絞り込み、`Take(100)`で「画面に表示できる最大件数」だけを取得します。人間は100件以上の選択肢を一度に見ることはできませんからね。
- `DataSource`の切り替え: `Items.Clear()`を繰り返すとちらつきの原因になります。`DataSource`を差し替える方が、内部的な再描画処理が最適化されます。
—
4. 初学者が陥りやすい罠とアドバイス
① 「TextChanged」イベントの過信
`TextChanged`は、プログラムから`DataSource`を書き換えた時にも発生します。無限ループを防ぐために、フラグ(`isUpdating`など)を立てて処理が重複しないように工夫してください。
② 大量描画の負荷
`Take(100)`の制限を忘れると、たとえ検索結果が1,000件あっても、ComboBoxは1,000件の描画を試みます。これがフリーズの原因です。「表示は最小限に」がUI設計の鉄則です。
③ データベースへの直接アクセスを避ける
`TextChanged`イベントの中で`SELECT FROM Customers WHERE Name LIKE …`を投げると、ネットワークの遅延でアプリが停止します。データは必ず一度メモリ(リスト)に読み込んでから検索してください。
—
最後に:エンジニアとしての視点
「数万件のデータを扱う」というのは、業務アプリにおいて一つの壁です。しかし、今日紹介したような「データ構造の分離」と「表示の最適化」を理解すれば、どんなに巨大なデータでも軽快に動くUIを作ることができます。
VB.NETは、こうした細かなパフォーマンスチューニングを直感的に行える素晴らしい言語です。一つひとつの処理が「なぜ重いのか」を考え、それを解消するコードを書く楽しさを、ぜひ現場で味わってください。
皆さんの開発が、よりスムーズで、より速いものになることを応援しています!また分からないことがあれば、いつでも聞きに来てくださいね。
