人気ブログランキング | 話題のタグを見る
(.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 を使えば再バインドなしでできるようです。時間あれば試してみたいと思います。
by jehoshaphat | 2010-04-18 07:24 | .Net開発


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