【发布时间】:2017-03-22 15:43:53
【问题描述】:
我有几个异步方法需要同步回主 ui 线程。
async Task MyAsyncMethod() {
await DoSomeThingAsync().ConfigureAwait(true);
DoSomethingInTheGui();
}
现在我需要从 gui 线程触发的同步事件处理程序中调用它们,并且事件处理程序在异步方法完成之前无法完成。所以MyAsyncMethod().Wait() 不是一种选择,也不是某种即发即弃的解决方案。
这种使用 Nito.AsyncEx 的方法看起来很有希望,但它仍然会死锁:https://stackoverflow.com/a/9343733/249456
我发现的唯一解决方案对我来说似乎是一个 hack:
public void RunInGui(Func<Task> action)
{
var window = new Window();
window.Loaded += (sender, args) => action()
.ContinueWith(p => {
window.Dispatcher.Invoke(() =>
{
window.Close();
});
});
window.ShowDialog();
}
有没有办法在不创建新窗口的情况下获得相同的效果(阻止调用方法,允许同步回gui线程)?
注意:我知道重构可能是最好的选择,但这是我们必须在较长时间内完成的一项艰巨任务。另外值得一提的是,这是 Autodesk Inventor 的插件。该 api 有几个怪癖,所有 API 调用(甚至与 ui 无关)都必须从 main/ui 线程执行。
另外值得一提的是,我们保留了对主线程调度程序的引用,并在代码库中使用MainThreadDispatcher.InvokeAsync(() => ... )。
【问题讨论】:
-
你不需要阻塞你的 UI 线程。只要您需要阻止您的 UI 线程(特别是当其他进程实际上需要使用 UI 线程时),那么您将处于一个受伤的世界。如果您重视自己的理智,请删除该要求。
-
为什么使用同步事件处理程序?为什么不是 *asynchronous& 事件处理程序?例如
async void Button_Click(..){ await MyAsyncMethod1(); await MyAsyncMethod2();} -
另一种选择是使用 Progress
将消息发送回 UI 线程。 Progress 的有效负载不必是字符串或进度消息,它可以是任何对象。检查Async in 4.5: Enabling Progress and Cancellation in Async APIs -
问题是事件处理程序不是“我的”。这是 Autodesk Inventor 的插件。我不能使用 async void 因为事件处理程序有参数:
void Eventhandler(..., out EventhandlingEnum handled)我需要确保在我的方法完成之前发明者主机应用程序不会继续
标签: c# async-await