BindingSourceクラス

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

コンストラクタ

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

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

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

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

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

メソッド

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

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

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

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

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

ResetBindings(Boolean) データバインドされているすべての項目を再読み込みし、表示している値を更新する。DataGridViewにバインドされているとき、そのDataGridViewRowのインスタンスが変更される。
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イベントを発生させている
  • 再読み込みされると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;
}
Microsoft Learnから検索