如何暂停在工作线程上运行的任务并等待用户输入?

问题描述:

如果我有一个在工作线程上运行的任务,当它发现有问题时,是否可以暂停并等待用户干预后再继续?

If I have a task running on a worker thread and when it finds something wrong, is it possible to pause and wait for the user to intervene before continuing?

例如,假设我有这样的事情:

For example, suppose I have something like this:

async void btnStartTask_Click(object sender, EventArgs e)
{
    await Task.Run(() => LongRunningTask());
}

// CPU-bound
bool LongRunningTask()
{
    // Establish some connection here.

    // Do some work here.

    List<Foo> incorrectValues = GetIncorrectValuesFromAbove();

    if (incorrectValues.Count > 0)
    {
        // Here, I want to present the "incorrect values" to the user (on the UI thread)
        // and let them select whether to modify a value, ignore it, or abort.
        var confirmedValues = WaitForUserInput(incorrectValues);
    }
    
    // Continue processing.
}

是否可以将 WaitForUserInput() 替换为在 UI 线程上运行的东西,等待用户的干预,然后采取相应的行动?如果是这样,如何?我不是在寻找完整的代码或任何东西;如果有人能指出我正确的方向,我将不胜感激.

Is it possible to substitute WaitForUserInput() with something that runs on the UI thread, waits for the user's intervention, and then acts accordingly? If so, how? I'm not looking for complete code or anything; if someone could point me in the right direction, I would be grateful.

你要找的几乎就是 Progress,除非你想让报告进度的东西得到一个任务返回一些信息,他们可以等待并检查结果.自己创建Progress并不是很难.,而且您可以合理地轻松适应以便计算结果.

What you're looking for is almost exactly Progress<T>, except you want to have the thing that reports progress get a task back with some information that they can await and inspect the results of. Creating Progress<T> yourself isn't terribly hard., and you can reasonably easily adapt it so that it computes a result.

public interface IPrompt<TResult, TInput>
{
    Task<TResult> Prompt(TInput input);
}

public class Prompt<TResult, TInput> : IPrompt<TResult, TInput>
{
    private SynchronizationContext context;
    private Func<TInput, Task<TResult>> prompt;
    public Prompt(Func<TInput, Task<TResult>> prompt)
    {
        context = SynchronizationContext.Current ?? new SynchronizationContext();
        this.prompt += prompt;
    }

    Task<TResult> IPrompt<TResult, TInput>.Prompt(TInput input)
    {
        var tcs = new TaskCompletionSource<TResult>();
        context.Post(data => prompt((TInput)data)
            .ContinueWith(task =>
            {
                if (task.IsCanceled)
                    tcs.TrySetCanceled();
                if (task.IsFaulted)
                    tcs.TrySetException(task.Exception.InnerExceptions);
                else
                    tcs.TrySetResult(task.Result);
            }), input);
        return tcs.Task;
    }
}

现在您只需要一个异步方法来接受来自长时间运行的进程的数据并返回一个带有任何用户界面响应的任务.

Now you simply need to have an asynchronous method that accepts the data from the long running process and returns a task with whatever the user interface's response is.