BackgroundWorkerの使い方 - C#

インスタンスを生成します。

BackgroundWorker  bw = new BackgroundWorker();
ここからは「bw」という名前で生成したインスタンスを使い、話を進めます。


バックグラウンド処理を実行する


DoWorkイベントにバックグラウンドで行う処理(イベントハンドラ)をフックします。
bw.DoWork += new DoWorkEventHandler(bw_DoWork);


バックグラウンド処理を実行する。
bw.RunWorkerAsync();

引数を渡す場合の例)
bw.RunWorkerAsync(100);

DoWorkイベントハンドラ内で渡された引数を使用する例)
int arg = (int)e.Argument;

DoWorkイベントハンドラの例)
void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bw = sender as BackgroundWorker;

    int i = 0, count = (int)e.Argument;

    while (i < count)
    {
        Thread.Sleep(100);
        bw.ReportProgress(++i);
        if (bw.CancellationPending)
        {
            e.Cancel = true;
            break;
        }
    }
}



処理をキャンセルする

BackgroundWorkerが非同期のキャンセルをサポートしているかどうかを示す値を設定します。
bw.WorkerSupportsCancellation = true;

キャンセルを要求します。
bw.CancelAsync();
CancellationPendingプロパティがtrueに設定されます。

処理がキャンセルされたかをDoWorkイベントハンドラ内でCancellationPendingプロパティを定期的にチェックする必要があります。
例)
BackgroundWorker worker = sender as BackgroundWorker;
if(worker.CancellationPending)
{
    //e.Cancel = true;
}

処理がキャンセルされた場合、RunWorkerCompletedイベントで処理がキャンセルされたことを知らせるにはDoWorkイベントハンドラ内で以下の処理を行います。
e.Cancel = true;

RunWorkerCompletedイベントにフックしたイベントハンドラで処理がキャンセルされたかどうかを取得する例を示します。
if (e.Cancelled) {
    MessageBox.Show("キャンセルされました。");
}

キャンセルの流れ
bw.CancelAsync()
    ↓
DoWorkイベントハンドラにて
worker.CancellationPendingプロパティがtrueになる。
    ↓
キャンセルされたことを知らせるため
e.Cancel = true
とする。
    ↓
処理を中断する。
    ↓
RunWorkerCompletedイベントハンドラにて
e.Cancelledプロパティがtrueになっている。



進行状況の更新

進行状況の更新を報告できるように設定します。
bw.WorkerReportsProgress = true;


ProgressChangedイベントにフックします。
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);


ProgressChangedイベントにフックするイベントハンドラの例)
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}
ProgressChangedイベントハンドラ内ではメインスレッドのコントロールにアクセス可能です。


進捗状況を更新します。
worker.ReportProgress(progressPercentage);
ReportProgressメソッドを実行するとProgressChangedイベントが発生します。
このメソッドの引数として渡した値がProgressChangedイベントにフックしたイベントハンドラでe.ProgressPercentageとして受け取ることができます。

他の引数を一つ渡すことが出来ます。
worker.ReportProgress(progressPercentage, "Working...");


Sample Code

public partial class Form1 : Form
{
    BackgroundWorker bw;

    public Form1()
    {
        InitializeComponent();
        progressBar1.Maximum = 100;

        bw = new BackgroundWorker();

        //BackgroundWorker が非同期のキャンセルをサポートしているかどうかを
        //示す値を取得または設定します。
        bw.WorkerSupportsCancellation = true;

        //プログレスバー関連
        //BackgroundWorker が進行状況の更新を報告できるかどうかを示す値を取得または設定します。
        bw.WorkerReportsProgress = true;

        //ReportProgress が呼び出されたときに発生します。
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

        //RunWorkerAsync が呼び出されたときに発生します。 
        //実際にバックグラウンド処理を行うイベントハンドラ
        //イベントにフックする。
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);

        //バックグラウンド操作の完了時、キャンセル時、
        //またはバックグラウンド操作によって例外が発生したときに発生します。
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    }

    private void btnExec_Click(object sender, EventArgs e)
    {
        //IsBusy - BackgroundWorker が非同期操作を実行中かどうかを示す値を取得します。
        if (!bw.IsBusy)
        {
            //バックグラウンド操作の実行を開始します。
            bw.RunWorkerAsync(100);
        }
    }

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Value = e.ProgressPercentage;
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bw = sender as BackgroundWorker;

        int i = 0, count = (int)e.Argument;
        while (i < count)
        {
            Thread.Sleep(50);
            bw.ReportProgress(++i);
            if (bw.CancellationPending)
            {
                e.Cancel = true;
                break;
            }
        }
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        string msg = string.Empty;

        if (e.Cancelled)
        {
            msg = "Cancelled";
        }
        else
        {
            msg = "Done";
        }

        MessageBox.Show(msg);

        progressBar1.Value = 0;
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        if (bw.IsBusy)
        {
            bw.CancelAsync();
        }
    }
}

0 Comments:

Recent Posts