(.Net)DataGridViewでバインドしたデータソースを変更してもグリッドには反映されない?でカスタムクラスのバインドについて書きました。
あの方法でバインドした DataGridView を下記のようにプログラム側から1行削除しようとしました。
public partial class Form1 : Form
{
//カスタムクラスのList。バインド元になるデータ。
List
mlst = new List ();
private void button1_Click(object sender, EventArgs e)
{
mlst.Add(new user("hogehoge1", "1"));
mlst.Add(new user("hogehoge2", "2"));
mlst.Add(new user("hogehoge3", "3"));
}
private void Form1_Load(object sender, EventArgs e)
{
//バインド。
//dataGridView1.DataSource = mlst;
}
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.Rows.RemoveAt(0);
}
}
//カスタムクラス。
public class user
{
public string name { get; set; }
public string id { get; set; }
public user(string sname, string sid)
{
name = sname;
id = sid;
}
}
Button1を押下しレコード追加後、Button2を押下してレコードを削除します。
その時、RemoveAt で下記の例外が発生しました。
System.InvalidOperationException はハンドルされませんでした。
Message="変更通知をサポートし、削除を許可する IBindingList に DataGridView がデータバインドされていない限り、プログラムで行を削除することはできません。"
Source="System.Windows.Forms"
StackTrace:
場所 System.Windows.Forms.DataGridViewRowCollection.RemoveAt(Int32 index)
場所 DataGridViewBindObjectTest.Form1.button2_Click(Object sender, EventArgs e) 場所 D:\mydoc\DataGridViewBindObjectTest\DataGridViewBindObjectTest\DataGridViewBindObjectTest\Form1.cs:行 65
...
で、調査してみました。
するとデータバインディングのおべんきょ。その5。で List をバインド対象として使わないほうがいいと書いてあります。理由として、List クラスが IBindingList インターフェイスを実装してないからみたいですね。
もうちょっと詳しい話が、MSDN:カスタム データ バインド (第 2 部)に下記のように書いてます。
BindingList
つまり、IListを継承した List
かといって、今更BindingListに直すのも面倒なんでいい方法が無いかいろいろ試してみました。
見つけたのが、MSDN:方法 : オブジェクトを Windows フォーム DataGridView コントロールにバインドするです。
BindingSource を使ってますね。
DataGridView → BindingSource → コレクション という感じに使うようです。
ただ、MSDNのチュートリアルでは BindingSource の Add メソッドでカスタムクラス単体を追加しています。
本来はこの方法か、iBindingList を実装したクラスでバインドするのが筋なんでしょうが、面倒なので、下記のようにしました。
public partial class Form1 : Form
{
List
mlst = new List ();
private void button1_Click(object sender, EventArgs e)
{
mlst.Add(new user("hogehoge1", "1"));
mlst.Add(new user("hogehoge2", "2"));
mlst.Add(new user("hogehoge3", "3"));
bindingSource1.DataSource = null;
bindingSource1.DataSource = mlst;
}
private void Form1_Load(object sender, EventArgs e)
{
DataColumn clm1 = new DataColumn("name");
mTbl.Columns.Add(clm1);
DataColumn clm2 = new DataColumn("id");
mTbl.Columns.Add(clm2);
dataGridView1.DataSource = bindingSource1;
}
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.Rows.RemoveAt(0);
}
}
public class user
{
public string name { get; set; }
public string id { get; set; }
public user(string sname, string sid)
{
name = sname;
id = sid;
}
}
BindingSource の DetaSource に List を指定しています。
とりあえずレコードの削除やDataGridView上の変更も List オブジェクトに反映されてるようです。
あんまきれいなやり方では無いですが、とりあえずこれでやってみることとしました。
今まで DataGridView にバインドしてたのは DataTable で楽してたんですが、他のコレクションをバインドするのは結構機能面の制約があって面倒ですね。。。