I currently have the following:
View Model
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;
}
In my MovieProcessor
class, I have the method 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);
}
}
The second time ReportProgress(x)
is called, I get the error:
This operation has already had OperationCompleted called on it and further calls are illegal.
CurrentProgress
is bound to my XAML
<ProgressBar Minimum="0" Maximum="{Binding MaxValueProgressBar}" Value="{Binding CurrentProgress, Mode=OneWay}" />
Would anyone have any idea as to what might be happening here?
To elaborate on the comment from dkozl:
It is possible that the async
is causing the problem. There's nothing in the code you posted that would cause an issue, but of course the code example you posted is far from complete.
If you have an await
statement in your processMovie_DoWork()
method (which is the usual reason one makes a method async
), then the method will execute only as far as the point of the first await
statement, and then it will exit.
As far as the BackgroundWorker
class is considered, this marks the end of the work. It has no way to know that some continuation would be called. Thus, when you call the ReportProgress()
method, the operation has in fact completed, making the call to ReportProgress()
illegal.
You have a couple of options here:
await
statements and perform those operations synchronously. Preferably by calling the synchronous version of the API.BackgroundWorker
and just call your processMovie_DoWork()
method directly (albeit likely renamed to something else). In this case, instead of calling the ReportProgress()
method, you'd just update the CurrentProgress
property directly.IMHO, the second option is much preferable. You can simply await
your processMovie_DoWork()
method, and avoid all the hassle of dealing with BackgroundWorker
.