在我的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内发生的事情需要额外的用户输入才能继续 . 为简单起见,假设用户只需单击“继续”按钮即可 .
我的问题是: how can I suspend the execution of GetResults in such a way that it awaits an event such as the click of another button?
这是实现我正在寻找的东西的一种丑陋方式:“继续”按钮的事件处理程序设置了一个标志......
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中发生的事情更复杂,并且在执行中的不同点可能需要不同类型的用户输入 . 因此,将逻辑分解为多种方法将是非常重要的 .
7 回答
您可以使用SemaphoreSlim Class的实例作为信号:
或者,您可以使用TaskCompletionSource<T> Class的实例创建表示按钮单击结果的Task<T>:
当你有一个不寻常的东西,你需要
await
,最简单的答案通常是TaskCompletionSource
(或一些基于TaskCompletionSource
的async
-enabled原语) .在这种情况下,您的需求非常简单,因此您可以直接使用
TaskCompletionSource
:从逻辑上讲,
TaskCompletionSource
就像async
ManualResetEvent
,除了你只能"set"事件一次,事件可以有"result"(在这种情况下,我们没有使用它,所以我们只是将结果设置为null
) .这是我使用的实用程序类:
以下是我如何使用它:
理想情况下,你没有 . 虽然你当然可以阻止异步线程,但这是浪费资源,并不理想 .
考虑用户在按钮等待点击时去吃午餐的规范示例 .
如果您在等待来自用户的输入时暂停了异步代码,那么它只是在该线程暂停时浪费资源 .
也就是说,点击一下就会's better if in your asynchronous operation, you set the state that you need to maintain to the point where the button is enabled and you'重新"waiting" . 那时,你的
GetResults
方法 stops .然后,单击该按钮时,根据您已存储的状态,启动另一个异步任务以继续工作 .
因为SynchronizationContext将在调用
GetResults
的事件处理程序中捕获(编译器将使用所使用的await
关键字执行此操作,并且SynchronizationContext.Current应该为非null,因为您在UI应用程序中),你可以这样使用async/await:ContinueToGetResultsAsync
是在按下按钮时继续获得结果的方法 . 如果未按下按钮,则事件处理程序不执行任何操作 .Stephen Toub发表了这个
AsyncManualResetEvent
类on his blog .Simple Helper Class:
Usage:
With Reactive Extensions (Rx.Net)
您可以使用Nuget Package System.Reactive添加Rx
Tested Sample: