我有幾個需要同步回主UI線程的異步方法。如何在異步方法運行時阻止方法而不會導致UI線程中的死鎖
async Task MyAsyncMethod() {
await DoSomeThingAsync().ConfigureAwait(true);
DoSomethingInTheGui();
}
現在我需要從從GUI線程引發了syncronous事件處理程序調用它們,以及事件處理程序無法完成,直到異步方法完成。所以MyAsyncMethod().Wait()
不是一種選擇,也不是某種「即丟即用」解決方案。
使用Nito.AsyncEx似乎有前途的這種做法,但它仍然死鎖:https://stackoverflow.com/a/9343733/249456
我發現的唯一的解決辦法似乎是一個黑客對我說:
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相關的)都必須從主/ UI線程執行。
另外值得一提的是,我們保留對主線程調度程序的引用,並在代碼庫中使用MainThreadDispatcher.InvokeAsync(() => ...)
。
你不需要屏蔽你的UI線程。只要你有阻止你的UI線程的要求(特別是當其他進程實際上需要使用UI線程時),那麼你將會處於一個受到傷害的世界。如果您重視您的理智,請刪除該要求。 – Servy
*爲什麼*使用同步事件處理程序?爲什麼不是一個*異步和事件處理程序?例如'async void Button_Click(..){await MyAsyncMethod1();等待MyAsyncMethod2();}' –
另一種選擇是使用進度將消息發送回UI線程。 Progress 的負載不一定是字符串或進度消息,它可以是任何對象。檢查[4.5中的異步:在異步API中啓用進度和取消](https://blogs.msdn.microsoft.com/dotnet/2012/06/06/async-in-4-5-enabling-progress-and-cancellation -in-async-apis /) –