DataGridViewのDataSourceにDataTableをバインドして、そのDataTableの内容をBackgroundWorkerで生成すると、アプリケーションがフリーズしてしまう現象が出ました。
具体的には、次のようなフォームを作ります。
フォームには、DataGridViewをdataGridView1という名前で貼り付けてあります。
このフォームに次のようなコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace DataGridViewTest
{
public partial class Form1 : Form
{
private DataTable m_table;
public Form1()
{
InitializeComponent();
// データテーブル生成
m_table = new DataTable();
m_table.Columns.Add(new DataColumn("id" , typeof(int)));
m_table.Columns.Add(new DataColumn("value", typeof(int)));
m_table.PrimaryKey = new DataColumn[] { m_table.Columns["id"] };
m_table.Columns["id"].AutoIncrement = true;
m_table.Columns["id"].AutoIncrementSeed = 1;
m_table.Columns["id"].AutoIncrementStep = 1;
}
private void Form1_Load(object sender, EventArgs e)
{
// データテーブルをDataGridViewにバインド
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = m_table;
// バックグラウンド処理開始
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Random rnd = new Random();
// データテーブルに1000行のデータを追加する
for (int index = 0; index < 1000; index++)
{
DataRow newRow = m_table.NewRow();
newRow["value"] = rnd.Next(100);
m_table.Rows.Add(newRow);
}
}
}
}
コンストラクタで、DataTableを生成しています。Loadイベントで、生成したDataTableをDataGridViewのDataSourceにバインドします(AutoGenerateColumnsをtrueにしてグリッドの列を自動生成しています)。そして、BackgroundWorkerで、DataTableに仮のデータを1000件作ります。
このコードをVisualStudioのデバッガで実行すると、
と表示されますが、グリッドにスクロールバーが表示されていません(ウインドウサイズを変更したりすると表示されます)。
このプログラムをReleaseでビルドして、実行ファイルを直接起動すると、プログラムがフリーズしてしまいます。
この現象は、
- .NET Framework2.0
- .NET Framework3.5
- .NET Framework4
デバッガでもスクロールバーが表示されないところがアヤシイので、いろいろ試してみたら、DataTableに追加するレコード(DataRow)が少ない時はフリーズしないことがわかり、よく見てみると、データ量が少ない=スクロールバーが表示される必要がない件数、であるようでした。
そこで、BackgroundWorkerでRunWorkerAsyncする前にDataGridViewのScrollBarsを一旦なしにして、BackgroundWorkerの処理が終了した時に、DataGridViewのScrollBarsを元に戻すようにしてみました。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace DataGridViewTest
{
public partial class Form1 : Form
{
private DataTable m_table;
public Form1()
{
InitializeComponent();
// データテーブル生成
m_table = new DataTable();
m_table.Columns.Add(new DataColumn("id" , typeof(int)));
m_table.Columns.Add(new DataColumn("value", typeof(int)));
m_table.PrimaryKey = new DataColumn[] { m_table.Columns["id"] };
m_table.Columns["id"].AutoIncrement = true;
m_table.Columns["id"].AutoIncrementSeed = 1;
m_table.Columns["id"].AutoIncrementStep = 1;
}
private void Form1_Load(object sender, EventArgs e)
{
// データテーブルをDataGridViewにバインド
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = m_table;
// グリッドのスクロールバーを一旦なしにする
dataGridView1.ScrollBars = ScrollBars.None;
// バックグラウンド処理開始
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Random rnd = new Random();
// データテーブルに1000行のデータを追加する
for (int index = 0; index < 1000; index++)
{
DataRow newRow = m_table.NewRow();
newRow["value"] = rnd.Next(100);
m_table.Rows.Add(newRow);
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// グリッドのスクロールバーを元に戻す
dataGridView1.ScrollBars = ScrollBars.Both;
}
}
}
こうすると、フリーズせずに動きました。
0 コメント :
コメントを投稿