The BackgroundWorker (BGW) uses a WindowFormsSynchronizationContext (SC) to invoke the completed and progress events on the UI thread. The SC comes from the thread that calls the RunWorkerAsync method. A non UI thread typically has no SC and then the BGW operates what is sometimes called the "free threaded model" using a ThreadPool thread to fire the completed and progress events. A BGW started from a new thread will behave properly if the thread is given the UI thread's SC. Some example code, I hope the missing bits are obvious.
private void StartFromThreadWithContext_Click(Object sender, EventArgs e) {
log.WriteLine("UI thread {0}", Thread.CurrentThread.ManagedThreadId);
Thread starterThread = new Thread(StarterThreadProc);
starterThread.Start(SynchronizationContext.Current);
}
private void StarterThreadProc(Object context) {
log.WriteLine("Starting BGW from thread {0}", Thread.CurrentThread.ManagedThreadId);
WindowsFormsSynchronizationContext wfsc = context as WindowsFormsSynchronizationContext;
if (wfsc != null) {
SynchronizationContext.SetSynchronizationContext(wfsc); // THE IMPORTANT BIT!!
}
log.WriteLine("Thread has {0}", SynchronizationContext.Current);
worker.RunWorkerAsync();
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
log.WriteLine("RunWorkerCompleted thread {0}", Thread.CurrentThread.ManagedThreadId);
}
private void Worker_DoWork(object sender, DoWorkEventArgs e) {
log.WriteLine("DoWork thread {0}", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(300);
}
Output to the log shows correct invocation of the completed event
UI thread 10
Starting BGW from thread 12
Thread has System.Windows.Forms.WindowsFormsSynchronizationContext
DoWork thread 7
RunWorkerCompleted thread 10
Alan.