小编典典

是否可以等待一个事件而不是另一个异步方法?

all

在我的 C#/XAML Metro 应用程序中,有一个按钮可以启动一个长时间运行的进程。因此,按照建议,我使用 async/await 来确保 UI
线程不会被阻塞:

private async void Button_Click_1(object sender, RoutedEventArgs e) 
{
     await GetResults();
}

private async Task GetResults()
{ 
     // Do lot of complex stuff that takes a long time
     // (e.g. contact some web services)
  ...
}

有时,GetResults 中发生的事情需要额外的用户输入才能继续。为简单起见,假设用户只需单击“继续”按钮。

我的问题是: 如何暂停 GetResults 的执行,以等待 诸如单击另一个按钮之类的 事件?

这是实现我正在寻找的一种丑陋的方式:“继续”按钮的事件处理程序设置了一个标志......

private bool _continue = false;
private void buttonContinue_Click(object sender, RoutedEventArgs e)
{
    _continue = true;
}

…并且 GetResults 定期对其进行轮询:

 buttonContinue.Visibility = Visibility.Visible;
 while (!_continue) await Task.Delay(100);  // poll _continue every 100ms
 buttonContinue.Visibility = Visibility.Collapsed;

轮询显然很糟糕(忙于等待/浪费周期),我正在寻找基于事件的东西。

有任何想法吗?

顺便说一句,在这个简化的例子中,一个解决方案当然是将 GetResults()
分成两部分,从开始按钮调用第一部分,从继续按钮调用第二部分。实际上,GetResults
中发生的事情更复杂,在执行过程中的不同点可能需要不同类型的用户输入。因此,将逻辑分解为多种方法并非易事。


阅读 68

收藏
2022-07-16

共1个答案

小编典典

您可以使用SemaphoreSlim 类的实例作为信号:

private SemaphoreSlim signal = new SemaphoreSlim(0, 1);

// set signal in event
signal.Release();

// wait for signal somewhere else
await signal.WaitAsync();

或者,您可以使用TaskCompletionSource的实例来创建表示按钮单击结果的Task

private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

// complete task in event
tcs.SetResult(true);

// wait for task somewhere else
await tcs.Task;
2022-07-16