C# BackGroundWorker with ProgressBar Updates after process complete - c#

I have the following in a button click event:
private void buttonSubmitAchChecks_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy) return;
SubmittingAch(true);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
label_Status.Text = "Submitting checks to ACH ....";
var qry = from ds in checkTrans.IndividualCheck
where ds.SubmitToACH &&
ds.Status == "Entered" &&
ds.CheckAmount > 0 &&
ds.SubmitToACH
select ds;
if (qry.Count() <= 0)
{
label_Status.Text = "Nothing to submit. Check the Check Amount, ACH, and Status fields.";
}
else
{
progressBar1.Maximum = qry.Count();
progressBar1.Minimum = 0;
progressBar1.Step = 1;
backgroundWorker1.RunWorkerAsync(qry);
}
}
My backgroundWorker1_DoWork:
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
}
else
{
var qry = e.Argument as EnumerableRowCollection<CheckTrans.IndividualCheckRow>;
if (qry != null)
{
Thread.Sleep(4000);
//item.Status = ach.SubmitCheck(item);
var ach = new SubmitAchChecks();
foreach (var item in qry)
{
ach.SubmitCheck(item);
backgroundWorker1.ReportProgress(1);
Console.Write("backgroundWorker1_dowork=" + progressBar1.Value.ToString() + "\r\n");
}
}
}
}
My Cancel Button:
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
label_Status.Text = "Cancelling...";
backgroundWorker1.CancelAsync();
}
}
My backgroundWorker1_RunWorkerCompleted:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
label_Status.Text = "Canceled!";
}
else if (e.Error != null)
{
label_Status.Text = "Error: " + e.Error.Message;
}
else
{
label_Status.Text = "Done!";
}
SubmittingAch(false);
}
My backgroundWorker1_ProgressChanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value += 1;
Console.Write("progressbar1.value=" + progressBar1.Value.ToString() + "\r\n");
}
I get following output in my debug window when I processed 2 items:
backgroundWorker1_dowork=0
backgroundWorker1_dowork=0
progressbar1.value=1
progressbar1.value=2
The event is firing, but as you can see from the console.write, it's happening AFTER the thread finishes. I get the progressbar scrolling, but only once the dowork has completed.
What have I done wrong on this? I'd like it to update as each item is completed.

It's due to the way threads work. ProgressChange is invoked on the UI thread using BeginInvoke, and therefore on another thread. Meanwhile, the worker thread continues running. Since there is not much work to do, the BackgroundWorker finishes its work before BeginInvoke actually invokes the method, because thread switches don't happen every CPU operation. They happen after quite a few. To avoid this, manually call the method that increments the ProgressBar's value using this.Invoke().

Related

How to correctly implement BackgroundWorker to inform user that the task is progressing

The Problem
I have used the project from https://github.com/zaagan/BioMetrix and want to use BackgroundWorker to display a progression during long tasks (Ex: Get Log Data takes about 30 seconds)
What I've done so far
1- Added backgroundWorker1 from Toolbox
2- After InitializeComponent(), I've Added :
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
3- Added those functions:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.Text = (e.ProgressPercentage.ToString() + "%");
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.Text = "Canceled!";
}
else if (e.Error != null)
{
this.Text = "Error: " + e.Error.Message;
}
else
{
this.Text = "Done!";
}
}
I was expecting to view the progression percentage on the main Caption title text while retrieving log data from the device.
You need to assign the event handler to the event
worker.DoWork += backgroundWorker_ProgressChanged;
If you have created a Windows Form you need to looking in events page of the Background Worker properties and find the DoWork event, then assign it a function to run.

how to return from the background worker to web UI in asp.net

background worker in asp.net does not write the content to the web UI when background worker completed. please tell me the reasons why. and how to recover.???
static BackgroundWorker bwProcess;
[WebMethod()]
public static int GetProgress()
{
return Percentage;
}
background worker starts when click event happen
protected void btnClick_Click(object sender, EventArgs e)
{
bwProcess = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
bwProcess.ProgressChanged += new ProgressChangedEventHandler(bwProcess_ProgressChanged);
bwProcess.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwProcess_RunWorkerCompleted);
bwProcess.RunWorkerAsync("AsyncWorker");
}
do work event for the backgroundworker
void bwProcess_DoWork(object sender, DoWorkEventArgs e)
{
bwProcess.ReportProgress(1);
for (int i = 0; i <= 100; i++)
{
if (bwProcess.CancellationPending)
{
e.Cancel = true;
return;
}
bwProcess.ReportProgress(i);
Thread.Sleep(20);
}
e.Result = "100 %";
}
this part is not working. it run nut there is no response
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Response.WriteFile("D:\\Samples.xlsx");
}
You've passed something to e.Result in DoWork, but you don't anything with it in RunWorkerCompleted.
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var text = e.Result as string;
Response.Write(text);
Response.WriteFile("D:\\Samples.xlsx");
}

Cancel out of DoWork and fall into RunWorkerCompleted

I have a BackgroundWorker in a WPF application. If a condition is true, I want to immediately stop processing the _DoWork method and go straight to the _RunWorkerCompleted. I'm using .CancelAsync, but the code after this point continues to execute.
How can I cancel out of my _DoWork and fall into _RunWorkerCompleted?
Example:
private BackgroundWorker step1 = new BackgroundWorker();
public MyWindow()
{
InitializeComponent();
step1.WorkerSupportsCancellation = true;
step1.DoWork += new DoWorkEventHandler(step1_DoWork);
step1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(step1_RunWorkerCompleted);
}
private void step1_DoWork(object sender, DoWorkEventArgs e)
{
if (someCondition)
{
step1.CancelAsync();
}
// code I do not want to execute
}
private void step1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// I want to jump here from the cancel point
}
CancelAsync is a method designed to be called by something other than the DoWork handler to indicate that the DoWork handler should stop executing. The DoWork handler should be checking to see if the BGW has requested cancellation and if so, stop executing (either by returning, throwing an exception, or otherwise not performing further work).
In your DoWork handler, check the cancellation state.
private void step1_DoWork(object sender, DoWorkEventArgs e)
{
if (someCondition)
{
step1.CancelAsync();
}
if (!step1.CancellationPending)
{
// code I do not want to execute
}
else
{
e.Cancel = true;
return;
}
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
}
}
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// This event handler updates the progress.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
resultLabel.Text = (e.ProgressPercentage.ToString() + "%");
}
// This event handler deals with the results of the background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}

How can i pause/continue backgroundworker?

I have a button click event for continue:
private void button3_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
button2.Enabled = true;
button3.Enabled = false;
}
else
{
backgroundWorker1.RunWorkerAsync();
button2.Enabled = true;
button3.Enabled = false;
}
}
And a button click event for pausing:
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
button3.Enabled = true;
soundPlay = false;
stop_alarm = true;
}
}
The problem is with the button3 click event the continue code sometimes the background is busy so i can enable false/true the buttons but the backgroundworker is keep working.
I want to pause the DoWork event and to continue.
This is my DoWork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (tempCpuValue >= (float?)numericUpDown1.Value || tempGpuValue >= (float?)numericUpDown1.Value)
{
soundPlay = true;
blinking_label();
}
else
{
soundPlay = false;
}
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
}
You could do this with a Thread instead of a BackgroundWorker?
With a Thread, in its working subroutine you could put the thread into an infinite sleep inside a try/catch block that catches ThreadInterruptedException. So, as it loops through whatever it's working on, you could look at the value of a boolean flag to know whether or not to sleep, and then call Thread.Sleep(Timeout.Infinite). When you catch ThreadInterruptedException you set the flag to false and continue to execute.
To make the thread resume from your UI, you would set the 'pause' flag to false and call workerThread.Interrupt() on your thread (assuming you called it workerThread, that is).
Idea sourced from here
You may need to wait until cancellation is done before enable/disable button.
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
//Wait statement goes here.
this.Cursor=Cursors.AppStarting;
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
button3.Enabled = true;
soundPlay = false;
stop_alarm = true;
}
}
Please see this question:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (tempCpuValue >= (float?)numericUpDown1.Value || tempGpuValue >= (float?)numericUpDown1.Value)
{
soundPlay = true;
blinking_label();
}
else
{
soundPlay = false;
}
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
_resetEvent.Set(); // signal that worker is done
}

Communicating with another thread

This is how I create a thread that does domething reps times:
protected virtual void RedButtonClicked(object sender, System.EventArgs e)
{
Nuker n = new Nuker(target, reps);
bombThread = new Thread(new ThreadStart(n.nuke));
bombThread.Start();
}
The thread class:
public class Nuker
{
private string target;
private int reps;
//...
public void nuke()
{
for(int i=0; i<reps; ++i)
{
ICBM.nuke(target);
Thread.Sleep(5500);
}
System.Console.WriteLine("Done.");
}
}
(I create a new class to store some variables since I can't pass these in ThreadStart().)
Now I would like to have a simple visualisation of the process, let's say printing the current repetition in a text field on a form. How would I use the i from the loop to do that?
In the simplest form you proved a callback in the Nuker class
public Nuker(string target, int reps, Action reportCallback){..}
In the loop you just call reportCallback(i);
Nuker n = new Nuker(target, reps, ReportMethod);
with
private void ReportMethod(int currentIdx)
{
if (InvokeRequired) // Invoke if UI update
...
}
But, probably you want to use the BackgroundWorker that has build in methods for reporting progress on the UI thread. Just check the examples on MSDN.
you can do it with a backgroundworker, it´s one of the easiest threads :-)
below i have post you a sample that i have createt to teach some friends the use of the backgroundworker ;-)
private BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
public void buttonStart_Click(object sender, EventArgs e)
{
if (bw.IsBusy != true)
bw.RunWorkerAsync(12); //Start
}
public int Pils(int i)
{
Thread.Sleep(2000);
bw.ReportProgress(70, "In the middle of the work..");
Thread.Sleep(2000);
bw.ReportProgress(90, "Returning the result..");
Thread.Sleep(2000);
return (2 * i);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
bw.ReportProgress(20, "Waiting for cancel..");
Thread.Sleep(2000);
if ((bw.CancellationPending == true))
e.Cancel = true;
else
{
bw.ReportProgress(50, "Starting process..");
e.Result = Pils((int)e.Argument);
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bw.ReportProgress(100, "Work done..");
if ((e.Cancelled == true))
textBox1.Text = "Canceled!";
else if (e.Error != null)
textBox1.Text = ("Error: " + e.Error.Message);
else textBox1.Text = e.Result.ToString();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
bw.CancelAsync();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add((e.ProgressPercentage.ToString() + "%") + " - " + e.UserState as String);
}
url to the blogpost: link

Categories

Resources