DataGrid への表示は、VB6 の頃から遅くて、表示更新をしないと早くなるという噂(けど真実)があったりします。
で、.NET になって DataGridView への DataSource プロパティへのバインドをすると早くなる、ってのが定番なんですが(セルへちまちま貼り付けるよりも早くなります…が、測定はしてないので、そのうちに)、なぜか、DataSource プロパティへのバインドをしているのに、とてつもなく遅くなる現象が発覚したので、晒します。
1.10 カラムある DataGridView を作ります。
2.データを作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /// <summary> /// データ作成 /// </summary> /// <returns></returns> private List<Data> MakeData() { List<Data> lst = new List<Data>(); for ( int i = 0; i < 3000; i++) { Data d = new Data(); d.Col1 = i.ToString(); d.Col2 = DateTime.Now.ToString(); d.Col3 = DateTime.Now.ToString(); d.Col4 = DateTime.Now.ToString(); d.Col5 = DateTime.Now.ToString(); d.Col6 = DateTime.Now.ToString(); d.Col7 = DateTime.Now.ToString(); d.Col8 = DateTime.Now.ToString(); d.Col9 = DateTime.Now.ToString(); d.Col10= DateTime.Now.ToString(); lst.Add(d); } return lst; |
3.データバインド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | private void button1_Click( object sender, EventArgs e) { var lst = MakeData(); // 自動でカラムを作らない dataGridView1.AutoGenerateColumns = false ; // 列幅はそのまま dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; Stopwatch sw = new Stopwatch(); sw.Start(); dataGridView1.DataSource = lst; sw.Stop(); MessageBox.Show( string .Format( "経過時間:{0} msec" , sw.ElapsedMilliseconds)); // 10 msec 程度 } |
普通に作るととても早いのですが…
1 2 | dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; |
このように、AutoSizeToAllHeaders を指定して列幅を自動で作成しようとすると。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private void button1_Click( object sender, EventArgs e) { var lst = MakeData(); // 自動でカラムを作らない dataGridView1.AutoGenerateColumns = false ; // 列幅を自動調節する dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; Stopwatch sw = new Stopwatch(); sw.Start(); dataGridView1.DataSource = lst; sw.Stop(); MessageBox.Show( string .Format( "経過時間:{0} msec" , sw.ElapsedMilliseconds)); // 4 分経ってもまだ終わりません。 } |
ってな具合に、1000 倍ぐらい遅くなります。
想像するに、DataSource プロパティでバインドしたデータが、1 件加わるごとに AutoSizeToAllHeaders で列幅を調節している感じなんですよね。なので、一度、EnableResizing で計算しないようにしてから、後で AutoSizeToAllHeaders を指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private void button1_Click( object sender, EventArgs e) { var lst = MakeData(); // 自動でカラムを作らない dataGridView1.AutoGenerateColumns = false ; // 列幅はそのままに変える dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; Stopwatch sw = new Stopwatch(); sw.Start(); dataGridView1.DataSource = lst; // 全て入力した後に列幅を自動調節する dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; sw.Stop(); MessageBox.Show( string .Format( "経過時間:{0} msec" , sw.ElapsedMilliseconds)); // 108 msec 高速に動作する } |
解決しました。ありがとうm(__)m
解決してよかったです。
テストのときに数十行では大したことがなくて、実際のデータで数千行を表示させたらとてつもなく遅くなった、というパターンに陥ります。
なぜか、DataGridView って1行追加するごとにヘッダの幅を再計算&再描画しているんですよね。。。ってことで、意外とハマります。