DataGridView へのバインドが遅い場合は、RowHeadersWidthSizeMode プロパティの値を疑ってみよう

DataGrid への表示は、VB6 の頃から遅くて、表示更新をしないと早くなるという噂(けど真実)があったりします。
で、.NET になって DataGridView への DataSource プロパティへのバインドをすると早くなる、ってのが定番なんですが(セルへちまちま貼り付けるよりも早くなります…が、測定はしてないので、そのうちに)、なぜか、DataSource プロパティへのバインドをしているのに、とてつもなく遅くなる現象が発覚したので、晒します。

1.10 カラムある DataGridView を作ります。
2.データを作成

/// <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.データバインド

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 程度

}

普通に作るととても早いのですが…

dataGridView1.RowHeadersWidthSizeMode = 
	DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;

このように、AutoSizeToAllHeaders を指定して列幅を自動で作成しようとすると。

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 を指定します。

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 高速に動作する
}

カテゴリー: 開発, C# パーマリンク

DataGridView へのバインドが遅い場合は、RowHeadersWidthSizeMode プロパティの値を疑ってみよう への2件のフィードバック

  1. hello のコメント:

    解決しました。ありがとうm(__)m

    • masuda のコメント:

      解決してよかったです。
      テストのときに数十行では大したことがなくて、実際のデータで数千行を表示させたらとてつもなく遅くなった、というパターンに陥ります。
      なぜか、DataGridView って1行追加するごとにヘッダの幅を再計算&再描画しているんですよね。。。ってことで、意外とハマります。

コメントは停止中です。