在另一个 AppDomain 中调用 Await 时没有 SynchronizationContext [英] No SynchronizationContext when calling Await in a another AppDomain
问题描述
我已经成功构建了一个插件机制,我可以在单独的 AppDomain 中创建 UI 控件,并将它们显示为主 AppDomain 中表单的一部分.
I have successfully built a plugin mechanism where I can create UI controls in a separate AppDomain and display them as part of a Form in the main AppDomain.
这些 UI 控件执行自己的数据加载,因此当我打开一个表单时,会创建大约 10 个不同的插件,每个插件都需要加载其数据.
These UI controls do their own data loading so when I open a form about 10 different plugins get created and each needs to load its data.
同样,如果我同步执行,这一切都很好,但我想在每个插件中使用 async/await 模式.我的刷新方法如下所示:
Again this all works fine if I do it synchronously but I would like to use the async/await pattern in each plugin. My refresh method looks like this:
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
OnDataChanged(); <= Worker Thread :(
}
现在问题开始了.当我进入这个方法时,我在主 UI 线程上.但是当等待结束时,我在一个工作线程上,所以我在更新控件的 OnDataChanged()
方法中得到一个跨线程异常.
Now here starts the problem. When I enter this method I am on the main UI thread. But when the await is over I am on a worker thread so I get a cross thread exception in the OnDataChanged()
method which updates the controls.
await
默认情况下应该使用 SynchronizationContext.Current
作为它的延续,但由于我在另一个 AppDomain 中,这恰好是 NULL.
await
should by default use the SynchronizationContext.Current
for its continuation but since I am in an other AppDomain this happens to be NULL.
所以我的问题是.如何配置 await 继续当前线程,即 UI 线程?
我知道我可以获取一个控件并执行 Invoke() 但我也在使用 MVVM 模式,这是在视图模型中,所以我无法访问那里的任何控件和所有视图模型 -> 视图通信是通过数据绑定完成.
I know I can grab a control and do Invoke() but I am also using the MVVM pattern and this is in the View Model so I don't have access to any controls there and all View Model -> View communications are done through data bindings.
推荐答案
我终于找到了如何在没有控件句柄的情况下从单独的 AppDomain 中返回 UI-Thread.
I finally figured out how to get back to the UI-Thread from within a separate AppDomain, without having a handle to a control.
由于我的视图模型总是在 UI 线程上实例化,我只是简单地获取当前的调度程序:
Since my view model is always instantiated on the UI thread, I simply grab the current dispatcher:
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher
现在在我的 RefreshData 方法中,我所要做的就是在等待之后调度我想要执行的操作.
Now in my RefreshData method all I have to do is dispatch the action I want to perform after the await.
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
_dispatcher.Invoke(() => OnDataChanged()); <= UI Thread :)
}
这当然可以做得更花哨,通过封装调度器等
This can of course be made more fancy, by encapsulating the dispatcher, etc.
这个想法实际上来自:MVVM Light Toolkit
这篇关于在另一个 AppDomain 中调用 Await 时没有 SynchronizationContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!