DataGridView:BindingSource でデータを検索・フィルタする(サンプルあり)

📋 目次(クリックで展開)

DataGridView に表示されている大量のデータから、テキストボックスに入力されたキーワードをもとに特定の行だけを抽出(絞り込み検索)したいケースは、業務システムにおいて極めて一般的です。

これを実装する際、データソースであるコレクション(List や DataTable)の中身をループや LINQ で毎回こねくり回して再バインドするコードを書くと、ロジックが複雑化しバグの原因になります。

このような「検索・絞り込み」のシナリオで絶大な威力を発揮するのが BindingSource コンポーネントです。データソースと DataGridView の間に BindingSource を仲介役として挟むことで、元のデータを一切破壊することなく、わずか1行のコードで瞬時に画面上のデータを絞り込むことができるようになります。

今回は、BindingSource を利用したリアルタイム検索画面の作成手順と、実務で直面する「絞り込み機能の強力な罠」について解説します。

BindingSourceでデータを絞り込む仕組み

BindingSource を使った検索の核心は、Filter プロパティの活用にあります。

BindingSource.Filter に、SQLの WHERE 句に似た文字列(例: "Name LIKE '%山田%'")を指定すると、BindingSource が背後でデータを自動的に間引き、DataGridView には条件に一致した行だけが透過的に表示されます。

条件をクリア(空文字を指定)すれば、元の全データが何事もなかったかのように一瞬で再表示されます。

実装コード

画面に テキストボックス(txtSearch)と DataGridView(dataGridView1)が配置されているものとします。テキストボックスに文字が入力されるたびに、リアルタイムに「商品名」で部分一致検索を行うコード例です。

Form1.cs
using System.Data;
namespace DataGridView_SearchBindingSource;
public partial class Form1 : Form
{
// 1. データの核となる DataTable
private DataTable _productTable = new DataTable();
// 2. データとUIを仲介する BindingSource
private BindingSource _productBindingSource = new BindingSource();
public Form1()
{
InitializeComponent();
InitializeData();
InitializeDataGridView();
}
private void InitializeData()
{
// テスト用データの準備
_productTable.Columns.Add("Code", typeof(string));
_productTable.Columns.Add("Name", typeof(string));
_productTable.Columns.Add("Price", typeof(int));
_productTable.Rows.Add("P001", "ノートパソコン", 120000);
_productTable.Rows.Add("P002", "USBメモリ", 2500);
_productTable.Rows.Add("P003", "液晶モニター", 35000);
_productTable.Rows.Add("P004", "ワイヤレスマウス", 4500);
_productTable.Rows.Add("P005", "メカニカルキーボード", 12800);
_productTable.Rows.Add("P006", "デスクトップパソコン", 110000);
}
private void InitializeDataGridView()
{
// 3. データ接続の「サンドイッチ構造」を作ります
// DataTable → BindingSource → DataGridView の順に紐付けます
_productBindingSource.DataSource = _productTable;
dataGridView1.DataSource = _productBindingSource;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
// 4. テキストボックスの文字変更イベント(リアルタイム検索用)を購読
txtSearch.TextChanged += TxtSearch_TextChanged;
}
/// <summary>
/// 検索テキストボックスの文字が書き換わるたびに呼び出されるイベント
/// </summary>
private void TxtSearch_TextChanged(object? sender, EventArgs e)
{
string keyword = txtSearch.Text.Trim();
if (string.IsNullOrEmpty(keyword))
{
// 検索ワードが空なら、フィルターを解除して全行表示に戻す
_productBindingSource.Filter = "";
}
else
{
// 入力された文字列内のシングルクォーテーションをエスケープ(後述)
string safeKeyword = keyword.Replace("'", "''");
// 5. Filterプロパティに条件式を代入(これだけでグリッドが瞬時に絞り込まれます)
// ※「Name列」を対象に、キーワードで部分一致(LIKE)検索を行う指示
_productBindingSource.Filter = $"Name LIKE '%{safeKeyword}%'";
}
}
}

サンプルアプリケーション

DataGridView_SearchBindingSource.zip
※ サンプルアプリケーションは、.NET 10 をターゲットに作成しています。

実行結果

↓ サンプルアプリケーションを実行すると、次の画面になります。

↓ 画面上部のテキストボックスに「パソコン」と入力すると、「ノートパソコン」、「デスクトップパソコン」のみが絞り込み表示されました。

BindingSource 検索の2つの注意点と対策

BindingSource.Filter は非常に強力ですが、実務のアプリケーションに組み込む際には、仕様を正しく理解していないと動かない致命的な落とし穴があります。

1. 通常の List<T>BindingList<T> では Filter は動かない

多くの開発者が「BindingSource.Filter が効かない!」と頭を抱える最大の原因がこれです。
実は、BindingSource.Filter という機能は、「裏側に紐付いている本当のデータソースが、検索機能をサポートしている場合」にしか動作しません。

内部的な話として、データソースが IBindingList インターフェースを実装しており、かつ SupportsFiltering プロパティが true を返す必要があります。

  • DataTable (DataView) ➡️ 検索に対応しているため動作します(上記サンプルコードで DataTable を採用しているのはこのためです)。
  • List<T>BindingList<T> ➡️ 標準仕様では検索に対応していないため、Filter に文字列を代入しても無視されるか、環境によってはエラーになります。

もしどうしても List<T>BindingList<T> のままで BindingSource.Filter を使いたい場合は、BindingList<T> を継承した独自のカスタムクラスを作成し、内部の検索ロジック(SupportsFilteringCoreApplyFilterCore)を自前でオーバーライドして実装するという非常に面倒な泥臭いコードが必要になります。そのため、検索画面を作る際は最初から素直に DataTable を基盤に選定するのが実務における最大の防衛策です。

2. シングルクォーテーション( ' )の入力による画面クラッシュ対策

Filter プロパティに渡す文字列は、内部的に簡易的なSQLクエリのように解析されます。そのため、ユーザーが検索ボックスに o'clockA's といった「シングルクォーテーション( ' )」を含むキーワードを入力すると、条件式の区切り文字のバランスが崩れ、システムが「構文エラー(EvaluateException)」を起こしてアプリが強制終了してしまいます。

実務のコードでは、ユーザーが何を打ち込んでもクラッシュしないように、サンプルコードのように、

string safeKeyword = keyword.Replace("'", "''");

を挟み、シングルクォーテーションを2個重ねてエスケープする防衛処理を入れておく必要があります。

まとめ

今回は、DataGridView の検索シナリオにおける BindingSource の具体的な活用手順について解説しました。
データを直接いじらず、中間に挟んだ BindingSource.Filter を操作するアプローチをとることで、検索ロジックを UI 側から切り離し、シンプルで堅牢な検索画面を構築できるようになります。

  • DataTable ➡️ BindingSource ➡️ DataGridView の階層構造でバインドする
  • BindingSource.Filter に条件式を入れるだけで、自動的に画面が絞り込まれる
  • 標準の List<T> では Filter が機能しないため、データ基盤には DataTable を推奨する
  • エラー落ちを防ぐため、キーワード内の ''' に置換する

次回は、この BindingSource の通貨管理(選択位置の同期)機能を活かした、もう一つの定番シナリオである「マスター・詳細入力欄の連動」について解説します。

DataGridView 関連記事


💬 コメント