こんばんは。きわさです。
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を使ってプログレスバーを更新する方法です。
