如何在异步方法中向UI提供反馈?

Fel*_*ani 8 .net c# asynchronous task winforms

我一直在开发一个Windows表单项目,我有10个任务要做,我想在async某种程度上这样做.当用户单击按钮并且我调用async方法执行此操作时,这些任务将会出现.在我的代码中,我已经有了这些进程的参数列表.

我的问题是:

A)如何转换我的代码并行运行所有进程?(我想实现async/await)

B)如何向我的UI应用程序提供反馈?

下面的代码是我试过的:

我的按钮调用方法来启动进程

private void button1_Click(object sender, EventArgs e)
{
    // almost 15 process
    foreach (var process in Processes)
    {
        // call a async method to process
        ProcessObject(process);
    }
}
Run Code Online (Sandbox Code Playgroud)

模拟我的进程获取参数的方法

private async void ProcessObject(ProcessViewModel process)
{
    // this is my loop scope, which I need to run in parallel
    {
       // my code is here

       // increment the progress of this process
       process.Progress++;

       // feedback to UI (accessing the UI controls)
       UpdateRow(process);
    }
}
Run Code Online (Sandbox Code Playgroud)

我试过这个,但我不确定它是否是更新我的UI(网格)的正确方法.

private void UpdateRow(ProcessViewModel process)
{
    dataGridView1.Rows[process.Index - 1].Cells[1].Value = process.Progress;
    dataGridView1.Refresh();
}
Run Code Online (Sandbox Code Playgroud)

Sco*_*ain 11

Sriram 在他的回答中介绍了如何进行异步/等待,但是我想向您展示另一种使用他的答案作为基础更新UI线程进度的方法.

.NET 4.5添加了IProgress<T>接口和Progress<T>类.内置的Progress类捕获同步上下文,就像async/await一样,然后当你去报告你的进度时,它会使用该上下文来进行回调(在你的情况下是UI线程).

private async void button1_Click(object sender, EventArgs e)
{
     var progress = new Progress<ProcessViewModel>(UpdateRow); //This makes a callback to UpdateRow when progress is reported.

     var tasks = Processes.Select(process => ProcessObject(process, progress)).ToList();
     await Task.WhenAll(tasks);
}

private async Task ProcessObject(ProcessViewModel process, IProgress<ProcessViewModel> progress)
{
    // my code is here with some loops
    await Task.Run(()=>
    {
        //Will be run in ThreadPool thread
        //Do whatever cpu bound work here


        //Still in the thread pool thread
        process.Progress++;

        // feedback to UI, calls UpdateRow on the UI thread.
        progress.Report(process); 
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯,为你的其他选择+1 (2认同)

Sri*_*vel 7

首先,对方法说" 不"async void(事件处理程序是例外),因为它内部抛出的异常不会被注意到.而是使用async Task并等待它.

private async void button1_Click(object sender, EventArgs e)// <--Note the async modifier
{
    // almost 15 process
    foreach (var process in Processes)
    {
        // call a async method to process
        await ProcessObject(process);
    }
}

private async Task ProcessObject(ProcessViewModel process)// <--Note the return type
{
    // my code is here with some loops
    await Task.Run(()=>
    {
        //Will be run in ThreadPool thread
        //Do whatever cpu bound work here
    });

    //At this point code runs in UI thread
    process.Progress++;

    // feedback to UI
    UpdateRow(process);
}
Run Code Online (Sandbox Code Playgroud)

但是,这将一次只启动一个任务,一旦完成,它将在下一个启动.如果你想立即启动所有这些,你可以启动它们并Task.WhenAll用来等待它.

private async void button1_Click(object sender, EventArgs e)// <--Note the async modifier
{
     var tasks = Processes.Select(ProcessObject).ToList();
     await Task.WhenAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)