3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.Net)DataGridViewでバインドしたListを変更してもグリッドには反映されない?

DataGridViewにカスタムクラスのListをバインドします。

そのカスタムクラスListにデータを追加したんですが、DataGridView に表示されません。

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

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;

}

}

//カスタムクラス。

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

}

}

 

//カスタムクラス。

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 を使えば再バインドなしでできるようです。時間あれば試してみたいと思います。