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

我一直在开发一个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); } } 

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

 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); } } 

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

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

首先,对async void方法说“ 不” (事件处理程序是例外),因为不会注意到它内部抛出的exception。 而是使用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); } 

但是,这将一次只启动一个任务,一旦完成,它将在下一个启动。 如果你想立即启动所有这些,你可以启动它们并使用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); } 

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

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

 private async void button1_Click(object sender, EventArgs e) { var progress = new Progress(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 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); }); }