Updating the user interface from a background thread that is called in a loop in the main user interface when the thread ends

I have a WinForms application that calls a business class method that does some heavy work, taking about 5 seconds for each call. The main form calls this method in a loop. This cycle can work from 10 times to, possibly, up to 10 thousand times.

The WinForms application sends the parameter to the business class and has an area that displays the time required for each method call and the value returned by this method. How can I tell my main window and update the text area in the main winform using the method that was returned for each call?

Currently, data is received immediately after the completion of all streams. Is there a way to update the interface for all iterations of the loop after each call? I do not mind if this is done consistently as well.

THE FORM

HeavyDutyClass hd; public Form1() { InitializeComponent(); hd = new HeavyDutyClass(); } //BUTTON CLICK private void Start_Click(object sender, EventArgs e) { int filecount = 5000; //BAD - opening 5000 threads! Any other approach? hd.FileProcessed += new EventHandler(hd_FileProcessed); var threads = new Thread[filecount]; for (int i = 0; i < filecount; i++) { threads[i] = new Thread(() => { hd.LongRunningMethod(); }); threads[i].Start(); } } //BUSINESS CLASS EVENT THAT FIRES WHEN BUSINESS METHOD COMPELTES void hd_FileProcessed(object sender, EventArgs e) { if (dgv.InvokeRequired) { dgv.Invoke((MethodInvoker)delegate { UpdateGrid(); }); } } private void UpdateGrid() { dgv.Rows.Add(1); int i = dgv.Rows.Count; dgv.Rows [ i-1].Selected = true; dgv.FirstDisplayedScrollingRowIndex = i - 1; } 

Business Heavy Duty class

  public event EventHandler FileProcessed; public HeavyDutyClass() { } protected virtual void OnMyEvent(EventArgs e) { if (FileProcessed != null) { FileProcessed(this, e); } } public bool LongRunningMethod() { for (double i = 0; i < 199990000; i++) { //time consuming loop } OnMyEvent(EventArgs.Empty); return true; } 
+4
source share
1 answer

Add the Winforms project, delete the control for the inscription on the form, copy-paste this code and press F5

[EDIT]: Updated with user business class commentary

NB . My form class is called Form3 . You may need to change your Program.cs or vice-versa.

 using System.ComponentModel; using System.Windows.Forms; namespace WindowsFormsApplication1 { public class BusinessClass { public int MyFunction(int input) { return input+10; } } public partial class Form3 : Form { private BackgroundWorker _worker; BusinessClass _biz = new BusinessClass(); public Form3() { InitializeComponent(); InitWorker(); } private void InitWorker() { if (_worker != null) { _worker.Dispose(); } _worker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; _worker.DoWork += DoWork; _worker.RunWorkerCompleted += RunWorkerCompleted; _worker.ProgressChanged += ProgressChanged; _worker.RunWorkerAsync(); } void DoWork(object sender, DoWorkEventArgs e) { int highestPercentageReached = 0; if (_worker.CancellationPending) { e.Cancel = true; } else { double i = 0.0d; int junk = 0; for (i = 0; i <= 199990000; i++) { int result = _biz.MyFunction(junk); junk++; // Report progress as a percentage of the total task. var percentComplete = (int)(i / 199990000 * 100); if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; // note I can pass the business class result also and display the same in the LABEL _worker.ReportProgress(percentComplete, result); _worker.CancelAsync(); } } } } void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { // Display some message to the user that task has been // cancelled } else if (e.Error != null) { // Do something with the error } } void ProgressChanged(object sender, ProgressChangedEventArgs e) { label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage); } } } 

With this, you can also easily cancel the functionality of Cancel. Notice that during initialization, I set WorkerSupportsCancellation = true and then check _worker.CancellationPending in DoWork. So, if you want to cancel the process using Cancel Button click , then you will write this code in the button handler - _worker.CancelAsync();

+8
source

All Articles