BindingSourceクラス

データソースとそれにバインドするコンポーネントの媒介とすることで、データの操作が容易になります。

DataTable table = new DataTable();

BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = table;
bindingSource.Filter = "col1 > 10"; // フィルタ
bindingSource.Sort = "col1 ASC";    // ソート

dataGridView.AutoGenerateColumns = true;
dataGridView.DataSource = bindingSource;

// BindingNavigatorと提携するならば、そのBindingSourceに設定する
bindingNavigator.BindingSource = bindingSource;
媒介手段としての BindingSource コンポーネント - BindingSource コンポーネントの概要 | Microsoft Learn

コンストラクタ

public BindingSource (
    object dataSource, // DataSourceプロパティに設定する値
    string dataMember  // DataMemberプロパティに設定する値
    );
BindingSource(Object, String) - BindingSource Constructor (System.Windows.Forms) | Microsoft Learn

引数のないコンストラクタBindingSource()の呼び出しは、BindingSource(null, String.Empty)とすることと同じです。BindingSource - Source Browser

プロパティ

プロパティ 内容
object DataSource バインドするデータソース。データソースの型に応じて、Listプロパティで公開されるRemarks - BindingSource.DataSource Property (System.Windows.Forms) | Microsoft Learn
string DataMember バインドするデータソース内の特定の列またはリストの名前
IList List バインドしているリスト
object Item[Int32] 指定のインデックスにある、リストの要素
object Current リスト内の、現在の項目
CurrencyManager CurrencyManager このBindingSourceに関連付けられているcurrency manager
string Filter 表示する行を決定するフィルタの式。式の構文はデータソースに依存する。既定はnull。
string Sort 並べ替えに使用する列の名前。既定はnull。記述方法はDataView.Sortと同じ
int Count フィルタが適用された状態での、項目の総数
bool RaiseListChangedEvents trueならば、ListChangedイベントが発生する

このListChangedイベントは、バインドしている項目が追加、削除、挿入や修正などによって変更されたときに発生する

このプロパティをfalseとしていた間に発生した変更は、ResetBindings()を呼ぶことで反映できる

     
Properties - BindingSource Class (System.Windows.Forms) | Microsoft Learn

DataSource

データソースには配列やリスト、それにIListSourceやITypedListを実装する型を設定できます。Remarks - BindingSource.DataSource Property (System.Windows.Forms) | Microsoft Learn

nullを指定したときは、同一の型の項目をリストとして管理できます。

BindingSource b1 = new BindingSource();
b1.DataSource = new[] { 1, 2 };

BindingSource b2 = new BindingSource();
b2.DataSource = new DataTable(); //  IListSourceを実装している

BindingSource b3 = new BindingSource();
b3.DataSource = null;
b3.Add(1);
b3.Add(2);

List

バインドしているリストを得られます。

DataTable table = new DataTable();
table.Columns.Add();
table.Rows.Add(0);
table.Rows.Add(1);
table.Rows.Add(2);
dataGridView.DataSource = table;

BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = table;

IList list = bindingSource.List;

int count = list.Count; // 3
DataRowView rowView = (DataRowView)list[0];
object.ReferenceEquals(rowView.Row, table.Rows[0]); // true

Count

DataTable table = new DataTable();
BindingSource bindingSource = new BindingSource(table, string.Empty);

int c1 = bindingSource.Count; // 0

table.Columns.Add("col1", typeof(int));
DataRowCollection rows = table.Rows;
rows.Add(1);
rows.Add(2);
rows.Add(3);
table.AcceptChanges();

int c2 = bindingSource.Count; // 3

bindingSource.Filter = "col1 < 3";
int c3 = bindingSource.Count; // 2

rows[0].Delete(); // Deleted
int c4 = bindingSource.Count; // 1

rows[0].AcceptChanges();
int c5 = bindingSource.Count; // 1

メソッド

メソッド 機能
SuspendBinding() データソースの更新からの変更を防止するため、データバインドを一時停止する

これを呼び出してもイベントの発生は抑制できない。これはTextBoxなどの単純なコントロールへのバインドを想定したもので、DataGridViewなどに対してはRaiseListChangedEventsをfalseとすることで対処するRemarks - BindingSource.SuspendBinding Method (System.Windows.Forms) | Microsoft Learn

SelectionChangedなどの、一部のイベントは抑制できる。

SuspendBinding() - BindingSource.cs
ResumeBinding() SuspendBinding()により停止していた、データバインドを再開する

一時停止していた間に発生した変更は、ResetBindings()を呼ぶことで反映できる

ResetBindings(Boolean) データバインドされているすべての項目を再読み込みし、表示している値を更新する
ResetItem(Int32) 指定位置の項目を再読み込みし、表示している値を更新する
RemoveFilter() フィルタを削除する。既定では、Filterプロパティにnullを設定するのと同じ
RemoveSort() 並べ替えを削除する。既定では、Sortプロパティにnullを設定するのと同じ
Add(Object) 内部リストに、指定の項目を追加できる
Remove(Object) 内部リストから、指定の項目を削除できる
IndexOf(Object) 指定の項目のインデックスを取得できる
Find(String, Object) 指定のプロパティが指定の値に一致する項目の、最初のインデックスを取得できる
   
Methods - BindingSource Class (System.Windows.Forms) | Microsoft Learn

UIスレッド以外からアクセスすると「BindingSource がそれ自体のデータ ソースであることはできません。DataSource および DataMember プロパティを、BindingSource に参照に帰る値に設定しないでください。(BindingSource cannot be its own data source. Do not set the DataSource and DataMember properties to values that refer back to BindingSource.)」としてInvalidOperationExceptionが投げられます。winforms - "BindingSource cannot be its own data source" - error when trying to reset the binding source from a method in another class - Stack Overflow

ResetBindings()

public void ResetBindings (bool metadataChanged);
BindingSource.ResetBindings(Boolean) Method (System.Windows.Forms) | Microsoft Learn

metadataChangedは、BindingSourceのデータ スキーマが変更されたならばtrue、項目の値だけが変更されたならばfalseとします。

  • RaiseListChangedEventsがfalseでは何も処理されないため、先にtrueに設定する
  • 内部ではOnListChanged()を呼ぶことで、ListChangedイベントを発生させている
  • DataGridViewにバインドされているとき、そのDataGridViewRowのインスタンスが変更される
  • 再読み込みされるとバインドしているDataGridViewのCurrentCellAddress.Xは0となり、SelectedCellsはそのセルだけとなる
bindingSource.RaiseListChangedEvents = false;

// DataSource の更新

bindingSource.RaiseListChangedEvents = true;
bindingSource.ResetBindings(false);

Find()

public int Find (
    string propertyName,
    object key
    );
Find(String, Object) - BindingSource.Find Method (System.Windows.Forms) | Microsoft Learn

propertyNameで指定するオーバーロードでは、その名前からPropertyDescriptorが取得されて、もう一方のオーバーロードが呼び出されます。Find - BindingSource.cs

このメソッドはリストのIBindingList.Find()を呼び出すだけであり、一致する項目がなかったときの動作は、その実装に依存します。複数の項目が一致したときには、最初のインデックスが返されます。

DataTable table = new DataTable();
table.Columns.Add("c1");
table.Columns.Add("c2");
table.Rows.Add(1, 2);
table.Rows.Add(3, 4);
table.Rows.Add(5, 6);
table.Rows.Add(5, 6);
dataGridView.DataSource = table;


BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = table;

dataGridView.DataSource = bindingSource;
int index1 = bindingSource.Find("c1", 3); // 1
int index2 = bindingSource.Find("c2", 6); // 2

データソースのフィルタで検索したときには、Listから一致する項目を見つけることで、そのインデックスを得られます。

DataRow[] rows = table.Select("c1 = 3");
DataRow target = rows[0];

int index = 0;
for (; index < bindingSource.List.Count; index++)
{
    DataRowView rowView = (DataRowView)bindingSource.List[index];
    if (object.ReferenceEquals(target, rowView.Row)) break;
}
// indexは、1

そのときフィルタも並べ替えも適用されていないならば、データソース内でのインデックスから得られます。

int rowIndex = table.Rows.IndexOf(target);         // データソース内での、インデックス

DataRowView rowView = table.DefaultView[rowIndex]; // そのインデックス位置にある、バインドされている項目
int index = bindingSource.IndexOf(rowView);        // バインドされている項目の、BindingSource内でのインデックス
// rowIndexとindexは一致する

DataGridViewにバインドされているとき、一致した項目が含まれる行は、その行にバインドされているオブジェクトと比較することで見つけられます。

foreach (DataGridViewRow viewRow in dataGridView.Rows)
{
    if (object.ReferenceEquals(((DataRowView)viewRow.DataBoundItem).Row, target)) break;
}

イベント

イベント 発生タイミング
ListChangedEventHandler ListChanged Listプロパティ内の項目が追加、除去、移動されたときやDataSourceやDataMemberが変更されたとき
Microsoft Learnから検索