等待输入而不阻塞同步代码的最佳方式



在WPF桌面应用程序中,我需要与采用同步回调功能的第三方API集成。在这个回调中,我需要显示第三方软件提供的消息,等待用户输入,然后将该输入返回给第三方程序。

与用户的交互将在我的主窗口中(而不是模式对话框(,因此在回调函数中不能阻止UI线程。

有很多方法可以做到这一点:线程&AutoResetEvent、DispatcherTimer等。但大多数描述这些方法的文章都是在.Net 4.5的异步功能出现之前写的。如今,还有什么理由做比以下更复杂的事情吗?

{
...
// Call 3rd party code passing our callback function
thirdParty.Process(referenceNumber, amount, GetValue))
...
}
// UI sets this variable from the user's input
private string _getValueResponse = null;
// The callback function passed to third party API
private void GetValue(ref ClientInstruction clientInstruction)
{
var message = clientInstruction.Message;
_getValueResponse = null;
// This event passes the 3rd party message to my main window,
// and causes it to prompt for user input.
GetValueRequired?.Invoke(this, new GetValueRequiredEventArgs(message));
var result = Task.Run<string>(
async () => await WaitForGetValueResponse())
.GetAwaiter().GetResult();
// Return user input to the third party code
clientInstruction.EnteredValue = result;
}
private async Task<string> WaitForGetValueResponse()
{
while (_getValueResponse == null)
{
await Task.Delay(100);
}
return _getValueResponse;
}

您可以使用类似BeginRead的模式来完成,如下所示

Task.Run(() => thirdParty.Process(referenceNumber, amount, GetValue)))
.ContinueWith();

Task.Run将启动新线程以获得用户输入并立即返回控制。GetValue一定是在阻止调用,因为第三方软件不希望它是异步的,不是吗?

ContinueWith()必须填充处理用户输入并将其返回到模型的逻辑

然而,我不确定这是否好。第一个问题是Task.Run生成新线程,并且UI对话框可能无法正确显示。但是,您可以使用WPF中的调度器来处理它。

我认为等待用户输入应该是blocking call,并且非阻塞输入没有太多好处。

您使用的是第三方软件,编写async GetValue将不起作用。

当说"在这种情况下无阻塞用户输入"时,您希望实现什么?

您正在启动另一个线程,只是为了等待结果。

需要明确的是,这里有三条线索在起作用。

  • 您的UI线程
  • 调用回调的线程
  • 使用Task.Run((启动的线程

这个第三个线程毫无意义,因为它所做的只是坐着等待UI线程的结果,而第二个线程坐着等待第三个螺纹!

如果你很高兴在等待时回调被阻止(你当前的代码就是这样做的(,为什么不只是睡眠呢?

private void GetValue(ref ClientInstruction clientInstruction)
{
var message = clientInstruction.Message;
_getValueResponse = null;
// This event causes the UI to prompt for input
GetValueRequired?.Invoke(this, new GetValueRequiredEventArgs(message));
//poll for response
while (_getValueResponse == null)
Thread.Sleep(100);
clientInstruction.EnteredValue = _getValueResponse ;
}

然而,我觉得这不对。我怀疑你的第三方API是否希望你锁定它的回调线程,尤其是当它为你提供了一个上下文对象来设置结果时?

你能不能不把ClientInstruction存储在一个成员中,然后直接从UI线程设置它?

最新更新