BackgroundWorker不退出循环

时间:2014-11-28 13:42:33

标签: c# backgroundworker

我有一个BackgroundWorker: BackgroundWorker worker;

private void Form1_Load(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;

worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += 
          new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += 
         new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}

DoWork活动

void worker_DoWork(object sender, DoWorkEventArgs e)
{
int percentFinished = (int)e.Argument;
while (!worker.CancellationPending && percentFinished < 100)
{
 percentFinished++;
 worker.ReportProgress(percentFinished);

 //here I start my operation
 //operation....
 //operation end

}
e.Result = percentFinished;
}

Progresschanged

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

已完成

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Asynchroner Thread kam bis zum Wert:
"+e.Result.ToString());
btnStartEnd.Text = "Starten";
}

最后我的按钮:

private void btnStartEnd_Click(object sender, EventArgs e)
{
   if (worker.IsBusy)
   {
   worker.CancelAsync();
   btnStartEnd.Text = "Starten";
   }
else
   {
     if (progressBar1.Value == progressBar1.Maximum)
      {
      progressBar1.Value = progressBar1.Minimum;
      }
    worker.RunWorkerAsync(progressBar1.Value);
    btnStartEnd.Text = "Stoppen";
   }
}

此代码有效但我得到了一个循环操作,直到百分比为100,因此操作开始100次,因此需要100倍。

目标应该是操作只开始一次,百分比从1-100开始。

也许我理解错了,但是工人怎么知道操作的进展程度呢?该值应发送到进度条以进行可视化。

2 个答案:

答案 0 :(得分:1)

通常,您不会在DoWork方法中添加循环 如果要从文件系统加载例如100个文件并报告进度,它可能如下所示:

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    for(int i = 0; i < 100; i++)
    {
        // Load file and do something with the content
        ...
        // Report the progress which causes the ProgressChanged event to be fired
        // And update progressbar with the UI thread
        worker.ReportProgress(i);                   
    }
}

如果您只有一个需要在DoWork方法中执行的长时间运行操作,则需要异步执行

以下是一个如何在.NET中异步调用操作的示例:

Action action = () =>
{
    for(int i = 0; i <100; i++)
    {
        Console.WriteLine(String.Format("Step {0} of long running operation", i));
        Thread.Sleep(1000);
    }
};

var r = action.BeginInvoke(null, null);
while(!r.IsCompleted)
{
    Console.WriteLine("Waiting...");
    Thread.Sleep(100);
}

但是在.NET中还有很多方法可以做到这一点。例如见:

答案 1 :(得分:1)

  

也许我理解错了,但是工人怎么知道操作的进展程度呢?该值应发送到进度条以进行可视化。

BackgroundWorker课程对您的操作及其进展一无所知。您的工作是确定何时报告进度。

通常,后台工作程序的工作流程如下所示:

  • UI线程调用RunWorkerAsync
  • DoWork在另一个线程上调用事件处理程序。在事件处理程序期间,您可以使用ReportProgress方法
  • 报告进度
  • 如果您报告进度,则在UI线程上调用ProgressChanged事件处理程序。在这里,您可以更新进度条,例如。
  • DoWork事件的事件处理程序退出时,会引发RunWorkerComplete事件。

为什么BackgroundWorker的每个示例都有一个for循环?因为它很容易编写,并且测量for循环的进度是微不足道的。不幸的是,这通常对不同类型的操作没有用。

如果您的长时间运行操作处理N个文件,那么很明显您可以在每个项目之后按1 / N更新进度条。这就是for-loop示例所做的。

但是如果你只有一个长时间运行的操作,那么你根本没有机会获得进展除非操作本身支持报告它或者你能以某种方式估计进度。

BackgroundWorker无法神奇地为长时间运行操作提供进度条。它只允许您在后台运行操作。