Passing an argument to backgroundWorker (for use as a cancel button)

I am new to C # and object oriented programming in general. I am trying to embed the Cancel button in my GUI so that the user can stop it in the middle of the process.

I read this question: How to implement the Stop / Cancel button? and determined that background work should be a good option for me, but the example below doesn’t explain how to pass arguments to backgroundWorker.

My problem is that I don't know how to pass an argument to backgroundWorker so that it stops the process; I was only able to make backgroundWorker stop.

I created the following code to try and find out where my form has two buttons (buttonStart and buttonStop) and backgroundWorker (backgroundWorkerStopCheck):

using System; using System.ComponentModel; using System.Windows.Forms; using System.Threading; using System.Timers; namespace TestBackgroundWorker { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Set the background worker to allow the user to stop the process. backgroundWorkerStopCheck.WorkerSupportsCancellation = true; } private System.Timers.Timer myTimer; private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e) { //If cancellation is pending, cancel work. if (backgroundWorkerStopCheck.CancellationPending) { e.Cancel = true; return; } } private void buttonStart_Click(object sender, EventArgs e) { // Notify the backgroundWorker that the process is starting. backgroundWorkerStopCheck.RunWorkerAsync(); LaunchCode(); } private void buttonStop_Click(object sender, EventArgs e) { // Tell the backgroundWorker to stop process. backgroundWorkerStopCheck.CancelAsync(); } private void LaunchCode() { buttonStart.Enabled = false; // Disable the start button to show that the process is ongoing. myTimer = new System.Timers.Timer(5000); // Waste five seconds. myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed); myTimer.Enabled = true; // Start the timer. } void myTimer_Elapsed(object sender, ElapsedEventArgs e) { buttonStart.Enabled = true; // ReEnable the Start button to show that the process either finished or was cancelled. } } } 

The code, if it worked correctly, would just sit there for five seconds after the user pressed the Start button before turning on the Start button again or quickly activated the Start button if the user pressed Stop.

There are two problems with this code that I'm not sure how to handle:

1) The myTimer_Elapsed method throws an InvalidOperationException when it tries to turn on the Start button because the "cross-flow operation is invalid." How to avoid cross-flow operations?

2) Currently, backgroundWorker is not doing anything because I don’t know how to give it arguments, so when it is canceled, it stops the timer.

I would be grateful for any help!

+4
source share
2 answers

First of all, the problem of avoiding "cross-thread operations is" invalid "is used by Invoke for controls. You cannot use a control from another thread.

About the second problem, I would implement it as follows. This is a minimal desktop with cancellation support.

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication5 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Set the background worker to allow the user to stop the process. backgroundWorkerStopCheck.WorkerSupportsCancellation = true; backgroundWorkerStopCheck.DoWork += new DoWorkEventHandler(backgroundWorkerStopCheck_DoWork); } private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e) { try { for (int i = 0; i < 50; i++) { if (backgroundWorkerStopCheck.CancellationPending) { // user cancel request e.Cancel = true; return; } System.Threading.Thread.Sleep(100); } } finally { InvokeEnableStartButton(); } } private void buttonStart_Click(object sender, EventArgs e) { //disable start button before launch work buttonStart.Enabled = false; // start worker backgroundWorkerStopCheck.RunWorkerAsync(); } private void buttonStop_Click(object sender, EventArgs e) { // Tell the backgroundWorker to stop process. backgroundWorkerStopCheck.CancelAsync(); } private void InvokeEnableStartButton() { // this method is called from a thread, // we need to Invoke to avoid "cross thread exception" if (this.InvokeRequired) { this.Invoke(new EnableStartButtonDelegate(EnableStartButton)); } else { EnableStartButton(); } } private void EnableStartButton() { buttonStart.Enabled = true; } } internal delegate void EnableStartButtonDelegate(); } 

About passing arguments to a worker, you can pass any object in the RunWorkerAsync() method and find it in the backgroundWorkerStopCheck_DoWork method:

  ... backgroundWorkerStopCheck.RunWorkerAsync("hello"); ... private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e) { string argument = e.Argument as string; // argument value is "hello" ... } 

Hope this helps.

+4
source

try this example and you will see how to transfer data to and from BackgroundWorker:

 public partial class Form1 : Form { BackgroundWorker bw = new BackgroundWorker(); public Form1() { InitializeComponent(); bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); bw.WorkerSupportsCancellation = true; } private void button1_Click(object sender, EventArgs e) { btnStart.Enabled = false; btnCancel.Enabled = true; double[] data = new double[1000000]; Random r = new Random(); for (int i = 0; i < data.Length; i++) data[i] = r.NextDouble(); bw.RunWorkerAsync(data); } void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnStart.Enabled = true; btnCancel.Enabled = false; if (!e.Cancelled) { double result = (double)e.Result; MessageBox.Show(result.ToString()); } } void bw_DoWork(object sender, DoWorkEventArgs e) { double[] data = (double[])e.Argument; for (int j = 0; j < 200; j++) { double result = 0; for (int i = 0; i < data.Length; i++) { if (bw.CancellationPending) { e.Cancel = true; return; } result += data[i]; } e.Result = result; } } private void btnCancel_Click(object sender, EventArgs e) { bw.CancelAsync(); btnStart.Enabled = true; btnCancel.Enabled = false; } } 
+3
source

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


All Articles