「ほっ」と。キャンペーン
(.Net)DataGridViewでバインドしたListを変更してもグリッドには反映されない?
DataGridViewにカスタムクラスのListをバインドします。
そのカスタムクラスListにデータを追加したんですが、DataGridView に表示されません。

ちょうどソースとしてはこんな感じです。


public partial class Form1 : Form
{
  //カスタムクラスのList。バインド元になるデータ。
List<user> mlst = new List<user>();

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;
}
}

//カスタムクラス。
public class user
{
public string name { get; set; }
public string id { get; set; }
public user(string sname, string sid)
{
name = sname;
id = sid;
}
}


Button1を押下したらデータソースとなっているListにデータを追加してるんで、DataGridViewにも反映してしてほしいんですが期待通りにはなりません。

下記のように button1_Click イベントの中で一旦 DataGridView.DataSource を null にして再バインドすると表示されました。

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"));
//一旦nullに
dataGridView1.DataSource = null;
//再バインド
dataGridView1.DataSource = mlst;
}


で、これでハッピー思ったんですが、 button1_Click イベント後表示されたセルをクリックすると、フォームの ShowDialog() でこんな例外が。。

System.IndexOutOfRangeException はハンドルされませんでした。
Message="インデックス -1 に値がありません。"
Source="System.Windows.Forms"
StackTrace:
場所 System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
場所 System.Windows.Forms.CurrencyManager.get_Current()
場所 System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e)
場所 System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred)
場所 System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick)
場所 System.Windows.Forms.DataGridView.OnCellMouseDown(HitTestInfo hti, Boolean isShiftDown, Boolean isControlDown)
場所 System.Windows.Forms.DataGridView.OnCellMouseDown(DataGridViewCellMouseEventArgs e)
場所 System.Windows.Forms.DataGridView.OnMouseDown(MouseEventArgs e)
場所 System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
場所 System.Windows.Forms.Control.WndProc(Message& m)
場所 System.Windows.Forms.DataGridView.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
場所 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.Run(Form mainForm)
場所 DataGridViewBindObjectTest.Program.Main() 場所 D:\mydoc\DataGridViewBindObjectTest\DataGridViewBindObjectTest\DataGridViewBindObjectTest\Program.cs:行 18
.....


で、Form1_Load イベントでのデータソースの設定を外すとこの例外がおきなくなりました。

public partial class Form1 : Form
{
//カスタムクラスのList。バインド元になるデータ。
List<user> mlst = new List<user>();

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;
}
}
 
//カスタムクラス。
public class user
{
public string name { get; set; }
public string id { get; set; }
public user(string sname, string sid)
{
name = sname;
id = sid;
}
}



DataTable をバインドしていると、下記のようにフォームロード時に一回 DataTable にバインドするだけで、後は何もしなくても自動で反映されるんですが、やはりカスタムクラスのバインドはひと癖あるようです。
public partial class Form1 : Form
{
DataTable mTbl = new DataTable();
 
private void button1_Click(object sender, EventArgs e)
{
DataRow row1 = mTbl.NewRow();
row1["name"] = "hoge1";
row1["id"] = 1;
mTbl.Rows.Add(row1);
DataRow row2 = mTbl.NewRow();
row2["name"] = "hoge2";
row2["id"] = 2;
mTbl.Rows.Add(row2);
//この時点でDataGridViewが更新される。
}
 
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 = mTbl;
}
}



追記:
コメントに書いてもらったように、Listではなく、BindingList を使えば再バインドなしでできるようです。時間あれば試してみたいと思います。
[PR]
by jehoshaphat | 2010-04-18 07:24 | .Net開発 | Trackback | Comments(6)
トラックバックURL : http://jehupc.exblog.jp/tb/12497729
トラックバックする(会員専用) [ヘルプ]
※このブログはトラックバック承認制を適用しています。 ブログの持ち主が承認するまでトラックバックは表示されません。
Commented by 自己流プログラマ at 2010-07-05 00:05 x
はじめまして、同様の悩みでここに来ました。
試行錯誤の結果、Loadの時点でというわけでなく
中身がリストが空っぽの状態でバインドすると
CurrencyManagerは、その最初の割り当てを
参考にアイテムを取得しようとするみたいで必ずコケるみたいです。

一旦、リストにダミーのカスタムクラスを登録した状態で
バインドすれば、直後にクリアしてもエラー落ちしませんでした。

むりやりですけど、私なりの回避方法です。(^^;
Commented by jehoshaphat at 2010-07-05 23:32
3流PGです。
なるほど。空リストだとダメなんですね。
参考になる回避方法の情報もありがとうございます。
Commented at 2010-07-07 19:56 x
ブログの持ち主だけに見える非公開コメントです。
Commented by 三輪の牛 at 2012-09-09 09:10 x
BindingList を使うと反映されると思います。
BindingList<user> mlst = new BindingList<user>();
Commented by Jehoshaphat at 2012-09-10 12:29
3流PGです。なるほど、BindingListを使えばいいんですね。追記させてもらいました。
Commented by ちゃー at 2013-06-07 09:28 x
BindingList、便利ですね。
助かりました~。


<< (.Net)DataGridV... (.Net)DataGridV... >>