C#のフォームアプリでBackgroundWorkerを使ってプログレスバーを更新する

こんばんは。きわさです。

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を使ってプログレスバーを更新する方法です。

スポンサーリンク