How to provide user interface feedback in an asynchronous method?

I am developing a windows forms project where I have 10 tasks and I would like to do this with async . These tasks will be displayed when the user clicks the button, and I call the async method to do this. In my code, I already have a list of parameters for these processes.

My questions:

A) How to convert my code for parallel operation of the whole process? (I would like to implement async / wait)

B) How to provide feedback to my user interface?

Below is the code I tried:

My button to call a method to start processes

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

A simulation method of my process receiving a parameter

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

I tried this, but I'm not sure if this is the right way to update my user interface (grid).

 private void UpdateRow(ProcessViewModel process) { dataGridView1.Rows[process.Index - 1].Cells[1].Value = process.Progress; dataGridView1.Refresh(); } 
+5
source share
2 answers

First of all, say no to async void methods (event handlers are exceptions) because the exceptions thrown inside it will not be noticed. Use async Task instead and wait for it.

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

However, this will only launch one task at a time, once this is done, it will start further. If you want to run all of them at once, you can run them and use Task.WhenAll to wait.

 private async void button1_Click(object sender, EventArgs e)// <--Note the async modifier { var tasks = Processes.Select(ProcessObject).ToList(); await Task.WhenAll(tasks); } 
+6
source

Sriram told how to make asynchronous / pending in his answer , however I wanted to show you another way to update progress in the UI thread using his response as a base.

.NET 4.5 added an IProgress<T> interface and a Progress<T> . The class built into Progress captures the synchronization context, like async / await, and then when you send a message about your progress, it uses this context for its callback (the UI thread in your case).

 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); }); } 
+8
source

Source: https://habr.com/ru/post/1202153/


All Articles