为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

九州编程 2019-07-29 17:14:45
是否有可能等待事件而不是另一个异步方法?在我的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中发生的事情更复杂,并且在执行中的不同点可能需要不同类型的用户输入。因此,将逻辑分解为多种方法将是非常重要的。
查看完整描述

3 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

如果你有一件不寻常的事情await,那么最简单的答案往往是TaskCompletionSource(或者是一些async基于原始的原语TaskCompletionSource)。

在这种情况下,您的需求非常简单,因此您可以直接使用TaskCompletionSource

private TaskCompletionSource<object> continueClicked;private async void Button_Click_1(object sender, RoutedEventArgs e) {
  // Note: You probably want to disable this button while "in progress" so the
  //  user can't click it twice.
  await GetResults();
  // And re-enable the button here, possibly in a finally block.}private async Task GetResults(){ 
  // Do lot of complex stuff that takes a long time
  // (e.g. contact some web services)

  // Wait for the user to click Continue.
  continueClicked = new TaskCompletionSource<object>();
  buttonContinue.Visibility = Visibility.Visible;
  await continueClicked.Task;
  buttonContinue.Visibility = Visibility.Collapsed;

  // More work...}private void buttonContinue_Click(object sender, RoutedEventArgs e){
  if (continueClicked != null)
    continueClicked.TrySetResult(null);}

逻辑上,TaskCompletionSource就像一个async ManualResetEvent,除了你只能“设置”事件一次,事件可以有一个“结果”(在这种情况下,我们没有使用它,所以我们只是设置结果null)。


查看完整回答
反对 回复 2019-07-29
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

这是我使用的实用程序类:


public class AsyncEventListener

{

    private readonly Func<bool> _predicate;


    public AsyncEventListener() : this(() => true)

    {


    }


    public AsyncEventListener(Func<bool> predicate)

    {

        _predicate = predicate;

        Successfully = new Task(() => { });

    }


    public void Listen(object sender, EventArgs eventArgs)

    {

        if (!Successfully.IsCompleted && _predicate.Invoke())

        {

            Successfully.RunSynchronously();

        }

    }


    public Task Successfully { get; }

}

以下是我如何使用它:


var itChanged = new AsyncEventListener();

someObject.PropertyChanged += itChanged.Listen;


// ... make it change ...


await itChanged.Successfully;

someObject.PropertyChanged -= itChanged.Listen;


查看完整回答
反对 回复 2019-07-29
  • 3 回答
  • 0 关注
  • 463 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信