在异步任务期间,有没有一种简单的方法可以在UI线程上执行方法?

时间:2019-01-18 09:45:22

标签: c# winforms async-await

在长时间执行以Task.Run()启动的异步方法期间,我可能需要找回用户以进行其他输入或确认,例如必须在UI线程上执行的消息框或文件对话框。

有一种简单的方法吗?

private void buttonApply_Click (object sender, EventArgs e) {
  try {
    // ...
    await executeAsync (_cts.Token, progress);
  } catch (OperationCanceledException) { }    
  // ...
}

private async Task executeAsync (CancellationToken cancellationToken, IProgress<string> progress) { 
  // ...      
  await Task.Run (() => execute (path, cancellationToken, progress), cancellationToken);
}

private void execute (string path, CancellationToken cancellationToken, IProgress<string> progress) {
  // do some work, report progress, check for cancellation
  // --> depending on initial work, request additional input via UI thread, how?
  // do more work, based on initial work and requested input
}

2 个答案:

答案 0 :(得分:2)

感谢您的评论,他们为我指明了正确的方向。我研究了System.Progress<T>的实现,我认为,我将从那里开始。

System.Progress<T>捕获SynchronizationContext,而Report(T value)调用同步上下文的异步Post()方法。

由于我需要调用的反馈,因此我将采用同步Send()方法,并且大概基于新的接口ICallbackQuery<T, TResult>或类似的IProgress<T>Progress<T>

答案 1 :(得分:0)

有一个名为ReactiveUI的框架-它使用ReactiveExtensions和Observables使MVVM的生活更轻松。

您无需深入研究并使用整个框架,但是它具有Interaction的简洁概念:

public class ViewModel : ReactiveObject
{
    private readonly Interaction<string, bool> confirm;

    public ViewModel()
    {
        this.confirm = new Interaction<string, bool>();
    }

    public Interaction<string, bool> Confirm => this.confirm;

    public async Task DeleteFileAsync()
    {
        var fileName = ...;

        // this will throw an exception if nothing handles the interaction
        var delete = await this.confirm.Handle(fileName);

        if (delete)
        {
            // delete the file
        }
    }
}

public class View
{
    public View()
    {
        this.WhenActivated(
            d =>
            {
                d(this
                    .ViewModel
                    .Confirm
                    .RegisterHandler(
                        async interaction =>
                        {
                            var deleteIt = await this.DisplayAlert(
                                "Confirm Delete",
                                $"Are you sure you want to delete '{interaction.Input}'?",
                                "YES",
                                "NO");

                            interaction.SetOutput(deleteIt);
                        }));
            });
    }
}

您可以只关注交互。

我还建议使用ReactiveCommand以避免按钮和异步操作出现问题。