471,337 Members | 874 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,337 software developers and data experts.

backgroundwork and progress

am having a hard time wrapping my head around "backgroundworker" class and
updates to the window form that calls it.

i have some questions about how to update windows form controls.
i have multiple labels and i'm using a text box for status updates.
the labels change when a task completes.
the text box report what task is running.

so
1) when i call _ProgressChange i need that function to passed the label i
want updating and what message?
2) does _ProgressChange know how to update the label and text box or do i
have to defind other parameters to link the windows form control to the
_ProgressChange.
3) if i have many functions that start after each other and they give status
do i need a different "backgroundworker" for each function? or can they be
tied to one thread? (each function relays on the first one to finish before
the next one starts).
does anyone or has anyone come across a good complex sample of a
"backgroundwork" class with multiple _ProgressChange?

Jun 27 '08 #1
10 1916
On May 16, 1:26 pm, auldh <au...@discussions.microsoft.comwrote:
am having a hard time wrapping my head around "backgroundworker" class and
updates to the window form that calls it.

i have some questions about how to update windows form controls.
i have multiple labels and i'm using a text box for status updates.
the labels change when a task completes.
the text box report what task is running.

so
1) when i call _ProgressChange i need that function to passed the label i
want updating and what message?
2) does _ProgressChange know how to update the label and text box or do i
have to defind other parameters to link the windows form control to the
_ProgressChange.
3) if i have many functions that start after each other and they give status
do i need a different "backgroundworker" for each function? or can they be
tied to one thread? (each function relays on the first one to finish before
the next one starts).

does anyone or has anyone come across a good complex sample of a
"backgroundwork" class with multiple _ProgressChange?
You don't call your objectName_ProductChanged method. You call the
instance method ReportProgress on the background worker. That method
handles doing the thread switching and raising the _ProgressChanged
event on the proper thread.

So you would have:

private void bworker1_DoWork( object sender, DoWorkEventArgs e ) {
BackgroundWorker worker;

worker = (BackgroundWorker)sender;

for ( int i = 0 ; i < 10 ; i += 1 ) {
worker.ReportProgress( i, null );
}
}

private void bworker1_ProgressChanged( object sender,
ProgressChangedEventArgs e ) {
myProgressBar.Value = e.ProgressPercentage * 10;
}

DoWork occurs on the background thread; all other event handlers for
the BackgroundWorker occur on the UI thread.

HTH
Andy
Jun 27 '08 #2
On Fri, 16 May 2008 10:26:01 -0700, auldh
<au***@discussions.microsoft.comwrote:
am having a hard time wrapping my head around "backgroundworker" class
and
updates to the window form that calls it.
It will be helpful if you first fully comprehend how Invoke() is used
absent a class like BackgroundWorker. Much of what BackgroundWorker does
is encapsulate the call to Invoke() so you don't have to deal with it. If
you don't understand Invoke(), it's hard to understand BackgroundWorker.
i have some questions about how to update windows form controls.
i have multiple labels and i'm using a text box for status updates.
the labels change when a task completes.
the text box report what task is running.

so
1) when i call _ProgressChange i need that function to passed the label i
want updating and what message?
What is "_ProgressChange"? How do you call it? There's no such method in
the BackgroundWorker class, so it's very difficult to know what you're
talking about.

If you really mean BackgroundWorker.ReportProgress(), which raises the
ProgressChanged event, then one overload of ReportProgress() takes an
Object as a parameter. This is copied to the
ProgressChangedEventArgs.UserState property. So you could pass the Label
you want updating, or a more complex class that references the Label and a
message string and anything else you want.
2) does _ProgressChange know how to update the label and text box or do i
have to defind other parameters to link the windows form control to the
_ProgressChange.
Again, what's "_ProgressChange"?

The BackgroundWorker class doesn't know anything about your own UI. All
it knows is to marshal the events ProgressChanged and RunWorkerCompleted
back to the thread on which the BackgroundWorker was created (if
possible...if you create it in a Forms application from the main GUI
thread, which is the usual use of the BackgroundWorker class, then it will
be possible). It is essentially calling Invoke() for you when raising the
ProgressChanged and RunWorkerCompleted events so that you don't have to.

You have to write all of the code to actually update your UI. That code
would go in your ProgressChanged event handler, and so of course you need
to make sure that all of the information that will be needed is passed at
the appropriate time, when you call BackgroundWorker.ReportProgress().
3) if i have many functions that start after each other and they give
status
do i need a different "backgroundworker" for each function? or can they
be
tied to one thread? (each function relays on the first one to finish
before
the next one starts).
Since the BackgroundWorker doesn't know anything at all about how you're
displaying progress, you can do it any way you like. If you want multiple
methods to be called from the same DoWork event of the same
BackgroundWorker, just call those methods from a single method that is
actually the DoWork event handler.
does anyone or has anyone come across a good complex sample of a
"backgroundwork" class with multiple _ProgressChange?
MSDN has sample code using BackgroundWorker. I recommend that you review
and learn that sample code well enough that you can discuss your use of
BackgroundWorker without using the wrong terminology. Once you're using
the correct terms and spelling for everything, it will be a lot easier to
understand your questions.

Pete
Jun 27 '08 #3
thanks Andy.
but what about the questions i have?

"Andy" wrote:
On May 16, 1:26 pm, auldh <au...@discussions.microsoft.comwrote:
am having a hard time wrapping my head around "backgroundworker" class and
updates to the window form that calls it.

i have some questions about how to update windows form controls.
i have multiple labels and i'm using a text box for status updates.
the labels change when a task completes.
the text box report what task is running.

so
1) when i call _ProgressChange i need that function to passed the label i
want updating and what message?
2) does _ProgressChange know how to update the label and text box or do i
have to defind other parameters to link the windows form control to the
_ProgressChange.
3) if i have many functions that start after each other and they give status
do i need a different "backgroundworker" for each function? or can they be
tied to one thread? (each function relays on the first one to finish before
the next one starts).

does anyone or has anyone come across a good complex sample of a
"backgroundwork" class with multiple _ProgressChange?

You don't call your objectName_ProductChanged method. You call the
instance method ReportProgress on the background worker. That method
handles doing the thread switching and raising the _ProgressChanged
event on the proper thread.

So you would have:

private void bworker1_DoWork( object sender, DoWorkEventArgs e ) {
BackgroundWorker worker;

worker = (BackgroundWorker)sender;

for ( int i = 0 ; i < 10 ; i += 1 ) {
worker.ReportProgress( i, null );
}
}

private void bworker1_ProgressChanged( object sender,
ProgressChangedEventArgs e ) {
myProgressBar.Value = e.ProgressPercentage * 10;
}

DoWork occurs on the background thread; all other event handlers for
the BackgroundWorker occur on the UI thread.

HTH
Andy
Jun 27 '08 #4
Auldh,
but what about the questions i have?
Then you should in my idea first give an explanation what your problem is.

Telling that you call _ProgressChange can be very misleading as Andy assumed
that you were invoking the event from the background class, however in fact
there is in my idea not direct a reason to expect thAT, it can be everything
else.

Cor

Jun 27 '08 #5
3) Seems like the operations you want to do in a separate thread are
dependent on one another. Putting heavy work on a separate thread is
ok to make sure your gui remains responsive. Make sure though, that
putting each operation in a separate thread is worth the overhead.
This is a good article:

http://www.yoda.arachsys.com/csharp/threads/

1 + 2 + does anyone or has anyone come across a good complex sample of
a
"backgroundwork" class with multiple _ProgressChange?

You might consider using the Observer pattern

http://en.wikipedia.org/wiki/Observer_pattern

and implement it using thread safe operations:

http://blog.devstone.com/aaron/archi...1/21/1351.aspx

Regards,
Joachim

Jun 27 '08 #6
thanks. i'm sorry if i'm not using the right terms.

i will try to be clearer as i try to explain my issues. i'm suppling a mock
up of my program. i put ":" in place where there is code not related to my
BackgroundWorker.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.VisualBasic;
using System.Threading;
namespace CallFlow
{

public partial class fCallFlow : Form
{

public fCallFlow()
{
InitializeComponent();
InitializeBackgroudWorker();
}
private void InitializeBackgroudWorker()
{
bgWorker.DoWork += new
System.ComponentModel.DoWorkEventHandler(this.bgWo rker_DoWork);
//bgWorker.ProgressChanged += new
ProgressChangedEventHandler(bgWorker_ProgressChang ed);
bgWorker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bgWorker_RunWorkerC ompleted);
}
private bool parseuserlog(string filename, string sfilename)
{
:
:
:
//do some work
// update the windows form giving status to the user
tbStatus.Text = "Reading the input file. Creating temp
files.\r\n";
:
//the code for heavy processing
:
:
}//private bool parseuserlog(string filename)

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
runProgram((string)e.Argument, worker, e);
}//private void bgWorker_DoWork(object sender, DoWorkEventArgs e)

private void bgWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
MessageBox.Show("Canceled");
this.bgWorker.CancelAsync();
}
else
{
MessageBox.Show("Done");
}
}//private void bgWorker_RunWorkerCompleted(oject sender,
RunWorkerCompletedEventArgs e)
private void bgWorker_ProgressChangeed(object sender,
ProgressChangedEventArgs e)
{
//e.UserState
//ProgressChangedEventArgs.UserState property
}

private void runProgram(string filename, BackgroundWorker worker,
DoWorkEventArgs e)
{
:
//check the windows form to see if a user option is set
if (cbTraces.Checked == true)
bTrace = true;
:
//get the file name to append to the output files.
sfilename = fileChoice.SafeFileName.Substring(0,
fileChoice.SafeFileName.IndexOf("."));
if (worker.CancellationPending)
{
e.Cancel = true;
}
//call the code that does the heavy process
if (!parseuserlog(filename, sfilename))
{
MessageBox.Show("Error in parseuserlog function.");
Application.Exit();
}
:
//provide a status to the window form
tbStatus.Text += "Starting to process the PHHONEMAIL script
data.\r\n";
tbStatus.Refresh();
if (worker.CancellationPending)
{
e.Cancel = true;
}
//code to call another heavy task
if (!parsephonemaildata2(sfilename))
MessageBox.Show("Error");
:
//provide a status to the window form
tbStatus.Text += "Starting to process the Vogue script data.\r\n";
tbStatus.Refresh();

//code to call another heavy task
if (!parsevoguedata2(sfilename))
{
MessageBox.Show("Error in parsevoguedata function.");
Application.Exit();
}
//provide status to the window form
tbStatus.Text += "Starting to process data AVERAGES.\r\n";
tbStatus.Refresh();
if (worker.CancellationPending)
{
e.Cancel = true;
}
//code to call another heavy task
getAverages(sfilename);

}//private void runProgram(string useless, BackgroundWorker worker,
DoWorkEventArgs e)

private void bProcess_Click(object sender, EventArgs e)
{
:
:
//code that starts when the user selects a window form button
:
//start the background thread
bgWorker.RunWorkerAsync(filename);
:
}//private void bProcess_Click(object sender, EventArgs e)

private bool parsephonemaildata2(string sfilename)
{
:
//heavy code task with no status to the window form
:
return (true);
}//private bool parsephonemaildata2()

private bool parsevoguedata2(string sfilename)
{
:
//code for heavy task.
//status to update windows form
tbStatus.Text += "Number of lines ran in VOGUE script: " +
lSessionID.ToString() + "\r\n";
:
return (true);
}//private bool parsevoguedata2()

private void fCallFlow_Load(object sender, EventArgs e)
{
tbVersion.Text = "Version 2.2";
}//private long convertsession(string sSession)

private void bCancel_Click(object sender, EventArgs e)
{
Application.Exit();
}

}//public partial class fCallFlow : Form
}//namespace CallFlow

the windows form "command" button calls "private void bProcess_click(object
sender, EventArgs e)" which when invoked calls the function "private void
runProgram( string useless, BackgroundWorker worker, DoWorkEventArgs e)".
this inturns fires off the worker thread that calls 3 heavy process
functions.

one such function "private bool parseuser(string filename, string
sfilename)" does a heavy number crunching task and has to give an update to
the windows form not to a progress bar but to TextBox which i want to give
verbal updates.

the first issue i have is that i'm not sure if the "worker" object can be
passed down to this function? if so what is the method for this?

i guess if i can do that i can figure it out for the other functions called
by the "runProgram" function that controls the thread. (i'm sorry if still
get the terms wrong).

the sample i found talk about simple process to the progress bar and only 1
level. they don't outline how to update labels, textboxes, and statusbars.

thanks for any help.
Jun 27 '08 #7
On Mon, 19 May 2008 12:46:15 -0700, auldh
<au***@discussions.microsoft.comwrote:
[...]
the first issue i have is that i'm not sure if the "worker" object canbe
passed down to this function? if so what is the method for this?
Of course it can. Just as you pass it to your runProgram() method, your
runProgram() method can pass it to subsequent methods that method calls.

Everywhere that you have code to update status (e.g. >tbStatus.Text +=
"Starting to process the PHHONEMAIL script data.\r\n" <<), you need to
replace that with a call to Invoke() that does the same thing, and get rid
of those calls to Refresh().

Pete
Jun 27 '08 #8
Peter can you expand on your comment:
Everywhere that you have code to update status (e.g. >tbStatus.Text +=
"Starting to process the PHHONEMAIL script data.\r\n" <<), you need to
replace that with a call to Invoke() that does the same thing, and get rid
of those calls to Refresh().
i can not see the forest through the trees. i can not find a good sample of
how to setup the Invoke method within a BackgroundWorker. seems samples use
the "progressbar" as their method of update.

so finding samples on updating labels, textbox and statusbar is difficult.

do i use "Delegate" and "InvokeRequired" in this operation?

"Peter Duniho" wrote:
On Mon, 19 May 2008 12:46:15 -0700, auldh
<au***@discussions.microsoft.comwrote:
[...]
the first issue i have is that i'm not sure if the "worker" object can be
passed down to this function? if so what is the method for this?

Of course it can. Just as you pass it to your runProgram() method, your
runProgram() method can pass it to subsequent methods that method calls.

Everywhere that you have code to update status (e.g. >tbStatus.Text +=
"Starting to process the PHHONEMAIL script data.\r\n" <<), you need to
replace that with a call to Invoke() that does the same thing, and get rid
of those calls to Refresh().

Pete
Jun 27 '08 #9
On Mon, 19 May 2008 16:46:37 -0700, auldh
<au***@discussions.microsoft.comwrote:
Peter can you expand on your comment:
>Everywhere that you have code to update status (e.g. >tbStatus.Text+=
"Starting to process the PHHONEMAIL script data.\r\n" <<), you need to
replace that with a call to Invoke() that does the same thing, and get
rid
of those calls to Refresh().

i can not see the forest through the trees. i can not find a good sample
of
how to setup the Invoke method within a BackgroundWorker. seems samples
use
the "progressbar" as their method of update.
Well, that's sort of the "approved" way to use a BackgroundWorker.
Because the ProgressChanged event is automatically marshaled onto the
correct thread, the Invoke() issue goes away.

And indeed, that would be one way to do it. You could just call
ReportProgress, passing an object that contains the information required
to perform the feedback (for example, a new string to append to a control
and possibly a reference to that control, though in the code you posted
you seem to only ever update one control so that wouldn't necessarily be
needed). Then in your ProgressChanged handler, just update the control
using the string.

For example, where you have some progress to report, it might look like
this:

worker.ReportProgress(0, "Starting to process the PHHONEMAIL script
data.\r\n");

Then in your handler, you'd do this:

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs
e)
{
tbStatus.Text += e.UserState.ToString();
}

An alternative (and this would be especially appropriate if you're already
using the ProgressChanged event for actual percentage progress updates)
would be to use Invoke() from your BackgroundWorker. In this case, it
would work the same as if you were doing it from any other thread; the
fact that the code is in the DoWork handler of BackgroundWorker is
somewhat irrelevant with this approach.

As an example, the code you have that currently looks like this:

tbStatus.Text += "Starting to process the PHHONEMAIL script data.\r\n";
tbStatus.Refresh();

Would instead look like this:

tbStatus.Invoke((MethodInvoker)delegate
{ tbStatus.Text += "Starting to process the PHHONEMAIL script
data.\r\n"; });

(Note that there's no need to call Refresh() :) )

Hope that helps.

Pete
Jun 27 '08 #10
Peter,
that worked and so easy to implement.

thanks!

"Peter Duniho" wrote:
On Mon, 19 May 2008 16:46:37 -0700, auldh
<au***@discussions.microsoft.comwrote:
Peter can you expand on your comment:
Everywhere that you have code to update status (e.g. >tbStatus.Text +=
"Starting to process the PHHONEMAIL script data.\r\n" <<), you need to
replace that with a call to Invoke() that does the same thing, and get
rid
of those calls to Refresh().
i can not see the forest through the trees. i can not find a good sample
of
how to setup the Invoke method within a BackgroundWorker. seems samples
use
the "progressbar" as their method of update.

Well, that's sort of the "approved" way to use a BackgroundWorker.
Because the ProgressChanged event is automatically marshaled onto the
correct thread, the Invoke() issue goes away.

And indeed, that would be one way to do it. You could just call
ReportProgress, passing an object that contains the information required
to perform the feedback (for example, a new string to append to a control
and possibly a reference to that control, though in the code you posted
you seem to only ever update one control so that wouldn't necessarily be
needed). Then in your ProgressChanged handler, just update the control
using the string.

For example, where you have some progress to report, it might look like
this:

worker.ReportProgress(0, "Starting to process the PHHONEMAIL script
data.\r\n");

Then in your handler, you'd do this:

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs
e)
{
tbStatus.Text += e.UserState.ToString();
}

An alternative (and this would be especially appropriate if you're already
using the ProgressChanged event for actual percentage progress updates)
would be to use Invoke() from your BackgroundWorker. In this case, it
would work the same as if you were doing it from any other thread; the
fact that the code is in the DoWork handler of BackgroundWorker is
somewhat irrelevant with this approach.

As an example, the code you have that currently looks like this:

tbStatus.Text += "Starting to process the PHHONEMAIL script data.\r\n";
tbStatus.Refresh();

Would instead look like this:

tbStatus.Invoke((MethodInvoker)delegate
{ tbStatus.Text += "Starting to process the PHHONEMAIL script
data.\r\n"; });

(Note that there's no need to call Refresh() :) )

Hope that helps.

Pete
Jun 27 '08 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

7 posts views Thread by Pepi Tonas | last post: by
1 post views Thread by scorpion53061 | last post: by
8 posts views Thread by Brian Henry | last post: by
8 posts views Thread by WhiteWizard | last post: by
1 post views Thread by daniel_xi | last post: by
15 posts views Thread by eladla | last post: by
5 posts views Thread by Aggelos | last post: by
reply views Thread by rosydwin | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.