在我的 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 中发生的事情更复杂,在执行过程中的不同点可能需要不同类型的用户输入。因此,将逻辑分解为多种方法并非易事。
您可以使用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;