1

ラジオボタンのクリックでトリガーされるバックグラウンドワーカーを処理する最良の方法を見つけようとしています。3 つのラジオ ボタンとラベルを持つ非常に単純なフォームを作成しました。各ラジオ ボタンは、同じイベント radioButton_CheckedChanged を共有します。イベントが完了したら、ラベルを「完了」に更新します。イベントが完了する前に別のラジオ ボタンをクリックすると、ラベルが Cancelled に更新されます。以下は、この簡単な例で書いたコードです。アプリケーションは期待どおりに実行される傾向がありますが、私の懸念は Application.DoEvents の使用です。これに対する私の代替手段は何ですか。明らかな理由で、IsBusy の間は眠れません。私はこれについてすべて間違っていますか、それともこれを行うためのより良い方法はありますか? ありがとう、ポコ

private void radioButton_CheckedChanged(object sender, EventArgs e)
{
  RadioButton rb = sender as RadioButton;
            if (rb.Checked)
            {
                if (backgroundWorker1.IsBusy)
                {
                    backgroundWorker1.CancelAsync();
                    while (backgroundWorker1.IsBusy)
                        Application.DoEvents();
                }

                backgroundWorker1.RunWorkerAsync();
            }
        }

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = 0; i < 100 && !worker.CancellationPending; ++i)
                Thread.Sleep(1);

            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
                label1.Text = "Canceled";
            else
                label1.Text = "Complete";
        }
4

2 に答える 2

7

BackgroundWorker が完了したときに実行する必要があるコードを RunWorkerCompleted ハンドラーに移動する必要があります。擬似コード:

private void radioButton_CheckedChanged(object sender, EventArgs e)
{
    // ...

    if (backgroundWorker1.IsBusy)
    {
        backgroundWorker1.CancelAsync();
        addJobToQueue();   // Don't wait here, just store what needs to be executed.
    } else {
        backgroundWorker1.RunWorkerAsync();
    } 
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled) {
        label1.Text = "Canceled";
    }
    else {
        label1.Text = "Complete";
    }

    // We've finished! See if there is more to do...
    if (thereIsAnotherJobInTheQueue())
    {
         startAnotherBackgroundWorkerTask();
    }
}
于 2010-10-28T21:31:49.343 に答える
0

DoEvents気軽に受け取られるべきではありません。より良い方法があります。非常に優れたものの 1 つは、ここ SO で説明されています。この答えはおそらくあなたに最適です。

したがって、ソリューションは次のようになります。

private AutoResetEvent _resetEvent = new AutoResetEvent(false);

private void radioButton_CheckedChanged(object sender, EventArgs e)
{
    RadioButton rb = sender as RadioButton;
    if (rb.Checked)
    {
        if (backgroundWorker1.IsBusy)
        {
            backgroundWorker1.CancelAsync();
            _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
        }

        backgroundWorker1.RunWorkerAsync();
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    for (int i = 0; i < 100 && !worker.CancellationPending; ++i)
        Thread.Sleep(1);

    if (worker.CancellationPending)
    {
        e.Cancel = true;
    }
    _resetEvent.Set();
}
于 2010-10-28T21:38:19.313 に答える