在另一个 AppDomain 中调用 Await 时没有 SynchronizationContext
No SynchronizationContext when calling Await in a another AppDomain
我已经成功地建立了一个插件机制,我可以在一个单独的 AppDomain 中创建 UI 控件,并将它们作为表单的一部分显示在主 AppDomain 中。
这些 UI 控件会自行加载数据,因此当我打开一个表单时,会创建大约 10 个不同的插件,每个插件都需要加载其数据。
同样,如果我同步执行这一切都很好,但我想在每个插件中使用 async/await 模式。我的刷新方法如下所示:
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
OnDataChanged(); <= Worker Thread :(
}
问题来了。当我进入这个方法时,我在主线程 UI 上。但是当等待结束时,我在工作线程上,所以我在更新控件的 OnDataChanged()
方法中得到一个跨线程异常。
await
默认情况下应该使用 SynchronizationContext.Current
来继续,但由于我在另一个 AppDomain 中,这恰好是 NULL。
所以我的问题是。如何配置 await 以继续当前线程,即 UI 线程?
我知道我可以获取一个控件并执行 Invoke() 但我也在使用 MVVM 模式,这是在视图模型中,所以我无权访问那里的任何控件和所有视图模型 -> 视图通信是通过数据绑定完成的。
我终于想出了如何从一个单独的 AppDomain 中返回到 UI-Thread,而无需控件的句柄。
因为我的视图模型总是在 UI 线程上实例化,所以我简单地获取当前调度程序:
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher
现在,在我的 RefreshData 方法中,我所要做的就是分派等待之后要执行的操作。
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
_dispatcher.Invoke(() => OnDataChanged()); <= UI Thread :)
}
这当然可以通过封装调度程序等变得更花哨
这个想法实际上来自:MVVM Light Toolkit
我已经成功地建立了一个插件机制,我可以在一个单独的 AppDomain 中创建 UI 控件,并将它们作为表单的一部分显示在主 AppDomain 中。
这些 UI 控件会自行加载数据,因此当我打开一个表单时,会创建大约 10 个不同的插件,每个插件都需要加载其数据。
同样,如果我同步执行这一切都很好,但我想在每个插件中使用 async/await 模式。我的刷新方法如下所示:
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
OnDataChanged(); <= Worker Thread :(
}
问题来了。当我进入这个方法时,我在主线程 UI 上。但是当等待结束时,我在工作线程上,所以我在更新控件的 OnDataChanged()
方法中得到一个跨线程异常。
await
默认情况下应该使用 SynchronizationContext.Current
来继续,但由于我在另一个 AppDomain 中,这恰好是 NULL。
所以我的问题是。如何配置 await 以继续当前线程,即 UI 线程?
我知道我可以获取一个控件并执行 Invoke() 但我也在使用 MVVM 模式,这是在视图模型中,所以我无权访问那里的任何控件和所有视图模型 -> 视图通信是通过数据绑定完成的。
我终于想出了如何从一个单独的 AppDomain 中返回到 UI-Thread,而无需控件的句柄。
因为我的视图模型总是在 UI 线程上实例化,所以我简单地获取当前调度程序:
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher
现在,在我的 RefreshData 方法中,我所要做的就是分派等待之后要执行的操作。
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
_dispatcher.Invoke(() => OnDataChanged()); <= UI Thread :)
}
这当然可以通过封装调度程序等变得更花哨
这个想法实际上来自:MVVM Light Toolkit