在同一个问题上,我找到了这个线程msdn。
这都与SynchronizationContext有关。
当Windows Forms创建一个窗口时,默认情况下会自动覆盖任何现有的SynchronizationContext;请参阅WindowsFormsSynchronizationContext.AutoInstall:
http://msdn.microsoft.com/en-us/library/system.windows.forms.windowsformssynchronizationcontext.autoinstall.aspx
BackgroundWorker在调用RunWorkerAsync时捕获SynchronizationContext,而不是在构造时(请注意,这是一个实现细节,未记录)。然后,它使用捕获的SynchronizationContext来执行RunWorkerCompleted。
因此,运行RunWokerCompleted的线程实际上是由RunWorkerAsync调用时的SynchronizationContext.Current确定的。
WPF提供了一个DispatcherSynchronizationContext,它将调用传递到其UI线程。Windows Forms提供了一个WindowsFormsSynchronizationContext,它将调用传递到其UI线程。在进行WPF/Forms互操作时,两个系统共享单个UI线程。您提到这都是在MFC应用程序的上下文中;在这种情况下,MFC不提供SynchronizationContext(当然),但它将与WPF和Forms线程共享其线程(它们都共享单个UI线程)。
还有一条信息:默认的SynchronizationContext将操作(例如,RunWorkerCompleted)排队到ThreadPool。这听起来就像您看到的行为。如果在调用RunWorkerAsync时SynchronizationContext.Current为空,则会出现此默认行为。
因此,关闭Windows Forms表单似乎会清除SynchronizationContext.Current。Windows Forms确实有一个“主表单”的概念,因此它可能会这样做,因为它认为应用程序的最后一个表单刚刚关闭。
我建议:1)测试在调用RunWorkerCompleted时SynchronizationContext.Current是否为空,并在显示Windows Forms表单之前和之后进行测试。只是为了确保这是问题所在。2)在Windows Forms表单关闭后设置SynchronizationContext.Current(通过SynchronizationContext.SetSynchronizationContext)。将“new DispatcherSynchronizationContext()”作为参数传递。
或者,如果Windows Forms表单是模态对话框,则可以使用我的Nito.Async库中的ScopedSynchronizationContext类(
http://www.codeplex.com/NitoAsync),它是一个非常简单的类,用于临时替换SynchronizationContext.Current,并在其“using”块结束时将其重置为其原始值。
有关各种SynchronizationContext类型的更多信息,请参阅我的博客:
http://nitoprograms.blogspot.com/2009/10/synchronizationcontext-properties.html
简而言之,插入
AsyncOperationManager.SynchronizationContext = new DispatcherSynchronizationContext(this.Dispatcher)
在调用RunWorkerAsync之前。
RunWorkerAsync
,我几乎可以保证回调不会在同一个线程上运行。 - Aaronaught