我有一个WPF对话框,其中包含一个进度条控件和一个后台任务(
在“正常”情况下,这一切都运作得很完美:
我注意到System.Progress文档说:
"[...]使用ProgressChanged事件注册的事件处理程序是通过在实例构造时捕获的SynchronizationContext实例调用的。如果在构造时没有当前的SynchronizationContext,则回调将在ThreadPool上调用。"
这似乎符合我的观察,因为在不良情况下,当
我检查了创建
为什么打开WinForms对话框会更改
System.Threading.Tasks.Task
),该任务提供了一系列需要输入到进度条中的进度更新。两者之间的中介是一个System.Progress<T>
对象。在“正常”情况下,这一切都运作得很完美:
- 后台任务在不是主线程X上调用
System.IProgress.Report()
。 System.Progress
对象进行其内部操作,切换线程。System.Progress
对象在主线程上触发ProgressChanged
事件。- 进度条控件在拥有该控件的主线程上更新。
我注意到System.Progress文档说:
"[...]使用ProgressChanged事件注册的事件处理程序是通过在实例构造时捕获的SynchronizationContext实例调用的。如果在构造时没有当前的SynchronizationContext,则回调将在ThreadPool上调用。"
这似乎符合我的观察,因为在不良情况下,当
System.Progress
触发其事件时,调用栈的下半部分看起来就像这样:[...]
bei System.Progress`1.InvokeHandlers(Object state)
bei System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
bei System.Threading.ThreadPoolWorkQueue.Dispatch()
bei System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
我检查了创建
System.Progress
对象时SynchronizationContext.Current
属性的值,但它从未为null。由该属性返回的SynchronizationContext
对象具有以下类型:
- 良好情况(即在打开WinForms对话框之前):该对象是
System.Windows.Forms.WindowsFormsSynchronizationContext
- 糟糕情况(即在打开WinForms对话框之后):该对象是
System.Threading.SynchronizationContext
SynchronizationContext
完全没有经验,因此我不知道发生了什么。为什么打开WinForms对话框会更改
SynchronizationContext.Current
的值?为什么这会影响System.Progress
的行为?除了编写自己的System.Progress
替代品,是否有解决问题的方法?
编辑:我可能需要补充的是,可执行文件在核心上是一个MFC应用程序,.exe项目使用/CLR编译,而我正在查看的C#代码是通过C++/CLI调用的。该C#代码编译为(并运行在).NET Framework 4.5.1下。这个复杂的设置是因为该应用程序是一个具有现代态度的遗留系统 :-),但到目前为止,这对我们来说非常有效。
System.Progress
实例是否不可行?您是否在应用程序的整个生命周期中使用同一个System.Progress
实例? - Felix CastorSystem.Progress
无关的场合,代码应该在主线程上运行,但却在其他线程上运行。我现在相信重置SynchronizationContext
是根本原因,我必须解决它,否则更邪恶的事情将在意想不到的角落出现。 - herzbube