6

我们有一个 WPF 和/或 Winforms 客户端正在使用的库。

我们提供了一个类似于以下的异步方法:

Task<int> GetIntAsync()

我们还(不幸地)提供了一个同步包装方法:

int GetInt();

它本质上只是调用异步方法并调用.Result其任务。

我们最近意识到在某些情况下,一些代码GetIntAsync需要在主 UI 线程上运行(它需要使用标记为“单”线程模型的遗留 COM 组件(即组件必须在主 STA 线程中运行,而不仅仅是任何STA线程)

所以问题是当GetInt()在主线程上调用时,它会死锁,因为

  • 阻塞主.Result线程,
  • 其中的代码GetIntAsync()用于Dispatcher.Invoke尝试在主线程上运行。

同步方法已被使用,因此删除它将是一项重大更改。因此,我们选择在我们的同步方法中使用WaitWithPumpingGetInt()来允许对主线程的调用工作。

GetInt()除了从他们的 UI 代码中使用的客户端外,这工作正常。以前,他们预计 usingGetInt()会使他们的 UI 无响应——也就是说,如果他们GetInt()从按钮的 click 事件处理程序中调用,他们预计在处理程序返回之前不会处理任何 Windows 消息。现在消息被抽出,他们的 UI响应式的,并且可以再次单击相同的按钮(并且他们可能没有将他们的处理程序编码为可重入)。

如果有一个合理的解决方案,我们不希望我们的客户在调用GetInt

问题:

  • 有没有办法WaitWithPumping可以抽出“调用到主”消息,但不抽出其他与 UI 相关的消息?
  • 如果客户端 UI 表现得好像当前显示了一个模态对话框,尽管它是隐藏的(即用户无法访问其他窗口),这对我们的目的来说就足够了。但是,根据我的阅读,您无法隐藏模式对话框。
  • 您能想到的其他解决方法将不胜感激。
4

1 回答 1

4

您可以在GetInt. 是一篇讨论如何编写的博客条目。 这是博客创建的完整解决方案

使用它,您可以将其编写为:

public int GetInt()
{
    return AsyncPump.Run(() => GetIntAsync());
}

这将导致按预期完全阻塞 UI 线程,同时仍确保从调用的所有延续GetIntAsync不会死锁,因为它们将被编组到不同的SynchronizationContext. 另请注意,此消息泵仍在主 STA/UI 线程上运行。

于 2013-02-11T20:59:52.110 回答