I'm having problems with BackgroundWorker
. It seems like it calls its Progress event in a different thread than it was created on, contrary to the documentation. First, for reference:
This is, when worker is being created:
This is, when worker is doing its job:
This is, when my code handles progress reported by the worker via ReportProgress
:
Note, that the last thread is even different from the previous two (main and BW's worker thread)
The worker is created in App.xaml.cs indirectly:
public App()
{
Configuration.Configure(Container.Instance);
// (...)
// Configure core service
coreService = Container.Instance.Resolve<ICoreService>();
coreService.Init();
}
And then:
public CoreService(ITfsService tfsService, IConfigurationService configurationService, IMapper mapper, IDialogService dialogService)
{
this.tfsService = tfsService;
this.configurationService = configurationService;
this.dialogService = dialogService;
worker = new CoreWorker(tfsService, configurationService);
worker.ProgressChanged += HandleCoreWorkerProgress;
}
Worker gets executed in CoreService.Init()
:
public void Init()
{
tfsService.Connect();
worker.RunWorkerAsync();
}
Worker itself looks more less like this:
private class CoreWorker : BackgroundWorker
{
private const int CORE_WORKER_TIMEOUT = 1000;
private readonly ITfsService tfsService;
private readonly IConfigurationService configurationService;
// (...)
public CoreWorker(ITfsService tfsService, IConfigurationService configurationService)
{
this.tfsService = tfsService;
this.configurationService = configurationService;
this.WorkerSupportsCancellation = true;
this.WorkerReportsProgress = true;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
while (true)
{
if (this.CancellationPending)
break;
if (EnsureTfsServiceUp())
{
(var startedBuilds, var succeededBuilds, var failedBuilds) = ProcessBuilds();
// Download and process builds
var buildResult = new BuildInfo(startedBuilds, succeededBuilds, failedBuilds);
ReportProgress(0, buildResult);
}
// Wait 1 minute
Thread.Sleep(CORE_WORKER_TIMEOUT);
}
}
}
Note, that interally I use async methods, but I wait for them explicitly (since I'm in a separate thread anyway):
(reachedSince, recentBuilds) = tfsService.GetBuilds(lastBuild.Value).Result;
runningBuilds = tfsService.GetBuilds(runningBuildIds).Result;
plannedBuilds = tfsService.GetBuilds(plannedBuildIds).Result;
Is there something I'm missing? Docs says, that progress handling should happen in the same thread as when BackgroundWorker
was created. But it is not, and I'm obviously getting errors on the UI.
Application is WPF, however it works in background, doesn't have main window, most of its job is done in the CoreService and it displays windows only occasionally.
How can I fix that, so that ReportProgress will run in the main thread?
Update: I modified my code to use Task
s instead and used Progress<T>
to process the progress:
notificationTask = Task.Factory.StartNew(async () => await ProcessNotifications(new Progress<BaseCoreNotification>(HandleNotificationProgress), notificationTaskCancellationSource),
notificationTaskCancellationSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).Unwrap();
Result is that the progress is still not processed in main thread.