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#, 開発   パーマリンク

コメントをどうぞ

メールアドレスが公開されることはありません。

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt="">