フォームの応答なしの症状と原因
フォームのボタンクリック等で、重いイベント処理を行うと応答なしとなり、バックグラウンドは処理しますが、画面は動作しなくなります。
重い処理をやっている間は、フォームのボタンなどの処理を受け取れないため、応答なしになります。
解決する方法としては、重い処理を別スレッドの処理で行います。
BackgroundWorkerクラスで解決
BackgroundWorkerインスタンス作成
BackgroundWorkerクラスは、重い処理を非同期的に別スレッドで処理を行うことのできるクラスです。
使い方は、ツールボックスからBackgroundWorkerを、対象のフォームへドラッグアンドドロップして追加します。
フォーム下に表示されるbackgroundWorker1を選択して、プロパティから雷マークをクリックして確認します。
今回は、DoWorkと、RunWorkerCompletedを使うので、項目にメソッド名をいれます。
ちなみに、機能としては以下の通り。
項目 | 機能 |
---|---|
DoWork | 操作が始まるときに別のスレッドでイベントハンドラーを実行します。 |
ProgressChanged | 状況が進歩したことをワーカースレッドが示すときに発生します。 |
RunWorkerCompleted | ワーカーが完了(成功、失敗またはキャンセルのいずれか)したときに発生します。 |
ソースコード
上記でイベント処理の設定すると、フォームクラスにメソッドが追加されます。
フォームクラスに、ドラッグアンドドロップで「backgroundWorker1」インスタンスが追加されているので、それを使って操作できます。
ソースコードは以下の通り。
private void button1_Click(object sender, EventArgs e)
{
// 重い処理のスレッドを立ち上げる
backgroundWorker1.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
// 重い処理を行う
for (long i = 0; i < 100000000; i++)
{
Console.WriteLine(i.ToString());
}
}
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// 重い処理を完了後、または失敗後に実施される。
MessageBox.Show("処理完了");
}
}
解説は上記のコメントの通りです。
重い処理を別スレッドにすることで、重い処理以外の処理は、並列に行われるので重い処理が終わるのを待つことはありません。
つまり、フォーム画面の処理は重い処理をやっている間も継続されるので、応答なしになったりしません。