こんばんは。きわさです。
C#でフォームアプリを作る際、プログレスバーで処理進捗を表示したいことありますよね。
今回は BackgroundWorker を使って実現する方法です。
以下のサンプルで説明します。
前提として、デザイナーでフォームアプリを作成し、開始ボタン(button1)、中止ボタン(button2)、プログレスバー(progressBar1)を配置しておく必要があります。
public partial class Form1 : Form { private bool isCanceled = false; private System.ComponentModel.BackgroundWorker backgroundWorker1; public Form1() { InitializeComponent(); // BackgroundWorkerインスタンスを生成し、イベントを設定 backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); backgroundWorker1.DoWork += backgroundWorker1_DoWork; backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted; return; } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { bool ret = true; // プログレスバーがMAXになるまでループ while (progressBar1.Value < progressBar1.Maximum) { if (isCanceled) { // キャンセルの場合は終了 ret = false; break; } // プログレスバーを更新 this.BeginInvoke(new UpdateProgressBarDelegate(updateProgressBar), new object[] { }); // 1秒待機 Thread.Sleep(1000); } // 結果をセット e.Result = ret; return; } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { this.BeginInvoke(new OnWorkerEndDelegate(onWorkerEnd), new object[] { (bool)e.Result }); return; } private void button1_Click(object sender, EventArgs e) { // キャンセルフラグをクリア isCanceled = false; // ボタン1を無効 button1.Enabled = false; // プログレスバーを初期化 progressBar1.Value = progressBar1.Minimum; // BackgroundWorker処理開始 backgroundWorker1.RunWorkerAsync(); return; } private void button2_Click(object sender, EventArgs e) { // キャンセルフラグをセット isCanceled = true; return; } private delegate void UpdateProgressBarDelegate(); private void updateProgressBar() { // プログレスバーを更新 progressBar1.PerformStep(); return; } private delegate void OnWorkerEndDelegate(bool result); private void onWorkerEnd(bool result) { if (result) { MessageBox.Show("終了しました。"); } else { MessageBox.Show("中止しました。"); } // ボタン1を有効 button1.Enabled = true; return; } }
順番に見ていきます。
まずForm1()ですが、以下の3行では、BackgroundWorkerインスタンスを生成してイベントを設定しています。
デザイナーで backgroundWorker を配置している場合は不要です。
// BackgroundWorkerインスタンスを生成し、イベントを設定 backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); backgroundWorker1.DoWork += backgroundWorker1_DoWork; backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
次にvoid backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)です。
これがBackgroundWorkerのメイン処理です。
1秒ごとにプログレスバーを更新し、MAXになるまで繰り返しています。
途中でキャンセルされた場合は終了します。
最後に e.Result を設定しています。これは処理の結果で、このあと呼ばれる処理からも参照することができます。
ポイントは以下の1行です。
// プログレスバーを更新 this.BeginInvoke(new UpdateProgressBarDelegate(updateProgressBar), new object[] { });
プログレスバーの更新は updateProgressBar() を直接呼び出せば良いような気もしますが、コントロールを生成したスレッドと別のスレッドから、コントロールを操作することはできないため、プログレスバーの更新は this.BeginInvoke でフォームに任せます。
次はvoid backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)です。
これは BackgroundWorker のメイン処理が完了したら呼ばれる処理です。
this.BeginInvoke(new OnWorkerEndDelegate(onWorkerEnd), new object[] { (bool)e.Result });
これは onWorkerEnd() に引数として (bool)e.Result を渡しています。
e.Resultは、DoWorkで設定した値です。参照する際は適切な型へキャストする必要があります。
onWorkerEnd() では、渡された引数によって結果メッセージを表示し、開始ボタンを有効化しています。
続いてvoid button1_Click(object sender, EventArgs e)です。
これは開始ボタン押下時の処理です。
フラグやプログレスバーを初期化し、ボタンを無効化しています。
その後、BackgroundWorker処理を開始しています。
// BackgroundWorker処理開始 backgroundWorker1.RunWorkerAsync();
そして、void button2_Click(object sender, EventArgs e)では、
中止ボタン押下処理として、フラグをセットしています。
以上が、BackgroundWorkerを使ってプログレスバーを更新する方法です。