Windows Formsにおけるデータバインディングの実装と応用

1. 単純データバインディング

単純データバインディングとは、コントロールの特定プロパティを、オブジェクトインスタンスのプロパティに結びつける仕組みです。実装形式は以下の通りです:

コントロール.DataBindings.Add("プロパティ名", オブジェクト, "バインド対象プロパティ", true);

下記はデータベースからデータを取得し、DataGridViewへバインドする例です。

using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connStr"].ToString()))
{
    const string query = "SELECT * FROM T_Class WHERE F_Type = 'Product' ORDER BY F_RootID, F_Orders";
    SqlDataAdapter adapter = new SqlDataAdapter(query, conn);
    DataSet ds = new DataSet();
    adapter.Fill(ds, "T_Class");

    // 方法1: DataSetによるバインド(DataMember指定が必要)
    this.dataGridView1.DataSource = ds;
    this.dataGridView1.DataMember = "T_Class";

    // 方法2: DataTable直接バインド
    this.dataGridView1.DataSource = ds.Tables["T_Class"];
}

また、 strongly-typed なリスト(例:IList<T>)も利用可能です:

IList<Student> studentList = StudentDB.GetAllList();
this.dataGridView1.DataSource = studentList;

列定義を明示しない場合、DataGridViewは自動的に全フィールド列を生成します。

2. 複合データバインディング

複合バインディングは、ListBoxComboBoxErrorProviderDataGridViewなどのリスト形式コントロールに、複数項目を含むデータソースを結びつけるものです。

サポート対象は以下の通りです:

  • IList 準拠のリスト(例:配列、ArrayListList<T>
  • IListSource を実装するオブジェクト(DataTableDataSet
  • IBindingList または IBindingListView インターフェース実装オブジェクト(例:BindingSource

BindingSourceコンポーネントを使用すると、任意の IEnumerable インターフェース実装オブジェクトもバインド可能です。

以下は、いくつかのデータセットでバインドする実装例です:

// ArrayList を用いたバインド
private ArrayList BuildArrayList1()
{
    ArrayList list = new ArrayList();
    list.Add(new PersonInfo("田中", "P001"));
    list.Add(new PersonInfo("鈴木", "P002"));
    return list;
}

// IDictionary エントリーを含むArrayList
private ArrayList BuildArrayList2()
{
    ArrayList list = new ArrayList();
    for (int i = 1; i <= 5; i++)
    {
        list.Add(new DictionaryEntry($"Key{i}", $"Val{i}"));
    }
    return list;
}

// DataTable の生成と埋め込み
private DataTable BuildDataTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("Value", typeof(string));

    for (int i = 1; i <= 5; i++)
    {
        DataRow row = dt.NewRow();
        row["Name"] = $"Item{i}";
        row["Value"] = $"Data{i}";
        dt.Rows.Add(row);
    }
    return dt;
}

// BindingSource を介した Dictionary<string,string> バインディング
private BindingSource BuildBindingSource()
{
    Dictionary<string, string> dict = new Dictionary<string, string>();
    for (int i = 0; i < 5; i++)
    {
        dict.Add($"ID{i}", $"Value{i}");
    }
    return new BindingSource(dict, null);
}

BindingSourceは、明示的な型情報を保持しつつ、非/IList実装オブジェクトもバインドできる強力なラッパーです。その構築方法は以下の2通りで、いずれも内部で強型列表現を生成します:

  • Add メソッドで個別要素を追加
  • DataSource プロパティにリスト・単一オブジェクト・型を設定

bindValue オプションとして、サポート可能なデータソースには次のようなものがあります:

// DataSet・DataTable
this.dataGridView1.DataSource = ds.Tables["Employees"];

// DataView
DataView view = new DataView(someTable);
this.dataGridView1.DataSource = view;

// ArrayList
ArrayList list = new ArrayList();
this.dataGridView1.DataSource = list;

// Dictionary<string,T>
Dictionary<string, Product> dic = GetProducts();
this.dataGridView1.DataSource = new BindingSource(dic, null);

// List<T> 包装
this.dataGridView1.DataSource = new BindingList<T>(sourceList);

3. 具体的な応用例

3.1 手動データソース設定(OLE DB 経由)

using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Restaurant.mdb"))
using (OleDbCommand cmd = new OleDbCommand("SELECT * FROM data", conn))
{
    OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);

    this.dataGridView1.DataSource = ds.Tables[0];
    this.dataGridView1.AutoGenerateColumns = false;
}

編集中行の更新ができない問題に対しては、編集状態を明示的に解除する処理が必要です:

this.dataGridView1.CurrentCell = null;
dataAdapter.Update(targetTable);

3.2 List<T> によるバインディング

private void Form1_Load(object sender, EventArgs e)
{
    List<Student> students = new List<Student>
    {
        new Student("Hathaway", "12", "Male"),
        new Student("Peter", "14", "Male"),
        new Student("Dell", "16", "Male"),
        new Student("Anne", "19", "Female")
    };
    this.dataGridView1.DataSource = students;
}

3.3 Dictionary<string,T> を利用する場合

private void Form1_Load(object sender, EventArgs e)
{
    Dictionary<string, Student> students = new Dictionary<string, Student>
    {
        ["Hathaway"] = new Student("Hathaway", "12", "Male"),
        ["Peter"] = new Student("Peter", "14", "Male"),
        ["Dell"] = new Student("Dell", "16", "Male"),
        ["Anne"] = new Student("Anne", "19", "Female")
    };

    BindingSource bs = new BindingSource();
    bs.DataSource = students.Values;
    this.dataGridView1.DataSource = bs;
}

3.4 SqlDataReader 経由で読み取り専用バインディング

using (SqlCommand cmd = new SqlCommand("SELECT * FROM product", DBService.Conn))
{
    SqlDataReader reader = cmd.ExecuteReader();
    BindingSource bs = new BindingSource(reader, null);
    this.dataGridView1.DataSource = bs;
}

3.5 SqlDataAdapter を用いた DataSet 充填

using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Product", DBService.Conn))
{
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    this.dataGridView1.DataSource = ds.Tables[0];
}

タグ: DataGridView DataSet datatable BindingSource IList

7月26日 02:21 投稿