使用进度条时出现"Operation already completed"错误



我目前有以下内容:

查看模型

MovieProcessor movieProcessor = new MovieProcessor(SelectedPath, this);
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += movieProcessor.processMovie_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
progressBar.Show();
worker.RunWorkerAsync();

worker_ProgressChanged

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

在我的MovieProcessor课上,我有方法processMovie_DoWork.

public async void processMovie_DoWork(object sender, DoWorkEventArgs e)
{
    for (int x = 0; x < totalFilesToProcess; ++x)
    {
         // Do stuff like calling API
         (sender as BackgroundWorker).ReportProgress(x);
    }
}

第二次调用ReportProgress(x),我收到错误:

This operation has already had OperationCompleted called on it and further calls are illegal.

CurrentProgress与我的XAML绑定

<ProgressBar  Minimum="0" Maximum="{Binding MaxValueProgressBar}"  Value="{Binding CurrentProgress, Mode=OneWay}" />

有人知道这里可能会发生什么吗?

详细说明 dkozl 的评论:

可能是async导致了问题。您发布的代码中没有任何内容会导致问题,但当然您发布的代码示例远未完成。

如果你在processMovie_DoWork()方法中有一个await语句(这是将方法async的通常原因),那么该方法将仅执行到第一个await语句的点,然后它将退出。

BackgroundWorker类而言,这标志着工作的结束。它没有办法知道会调用一些延续。因此,当您调用 ReportProgress() 方法时,操作实际上已完成,因此调用 ReportProgress()非法。

您在这里有几个选择:

  1. 删除await语句并同步执行这些操作。最好通过调用 API 的同步版本。
  2. 摆脱BackgroundWorker,直接调用processMovie_DoWork()方法(尽管可能重命名为其他名称)。在这种情况下,只需直接更新 CurrentProgress 属性,而不是调用 ReportProgress() 方法。

恕我直言,第二种选择更可取。您可以简单地await processMovie_DoWork()方法,并避免处理BackgroundWorker的所有麻烦。

我刚刚遇到此问题,尝试使用后台工作线程从 Web API 轮询状态。我通过删除async并将await运算符更改为 Task.Wait() 来解决此问题,并且效果很好。

这是我的代码代替"// Do stuff like calling API":

var task = JobManager.GetJobStatus(id);
task.Wait();
var status = task.Result;

我希望这对其他人有所帮助。我相信你克服了这个问题。

相关内容

最新更新