multiple progressbar with backgroundworker

  • Thread starter Thread starter auldh
  • Start date Start date
A

auldh

hello,

i'm having problems getting my three progressbar getting updates.

i created the backgroundworker and enabled the "WorkerReportsProgress =
true". i specified the 3 progressbars in the "private void
bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)".

the back ground worker calls a function, that function is doing construction
of a multiple collection so i want to give the user progress via the
progressbar. but i'm not getting the progressbar to show any progress.

originally i had "private void ListLDN_Start(string[] filenames,
BackgroundWorker worker, DoWorkEventArgs e)" call the three functions with
out including "BackgroundWorker worker, DoWorkEventArgs e". but even if i
continue to pass the background worker i'm still not getting updates.

i'm not understanding or finding any samples on the internet that explain or
help me conquer my problem.

what i'm i doing wrong/missing? clearly i'm doing it wrong but not
successful in finding the problem.

//sample of code...
private void ListLDN_Start(string[] filenames, BackgroundWorker
worker, DoWorkEventArgs e)
{
//starting conerting the listldn into a comma delimited file
:
:
//start the body of the work
lcount = build_master_gspfile(filenames);
build_master_gsparray(lcount, worker, e);
compare_files(lcount, filenames);
//finish the body of the work
}

private int build_master_gspfile(string[] filenames)
{
int lcount = 0; // file list incrementer to walk through the
file list
string data = null; //ra dta string read from input file then
stored in ouput file for later
string temp1 = null, temp2 = string.Empty, site_number = null;
int comma = 0, quote = 0, a = 0;
bool peg = false; //use this to gauge if a record was matched

lcount = 0;

//master file stored in program dir.
StreamWriter sw = new StreamWriter(master_file);
try
{
for (lcount = 0; lcount < filenames.Length; lcount++)
{
:
:
worker.ReportProgress(iSite / 16);
:
:
}//while (sinput.Peek() >= 0)
//should peg not set to turn there was an error in the
gsp file with
//its own site number
if (peg == false)
{
MessageBox.Show("Process stopped because local site
number (" + temp1 +
") is missing in its own file: " +
filenames[lcount] +
". Program error, system Abort.");
Application.Exit();
}
}//for(lcount = 0; lcount < filenames.Length; lcount++)
}
catch (Exception err)
{
ErrorFile ef = new ErrorFile();
:
:
}
sw.Close();
return lcount;
}//private void build_master_gspfile()

private void build_master_gsparray(int lcount, BackgroundWorker
worker, DoWorkEventArgs e)
{
//open the gsp master file and load the master gsp array
int iSite = 0, iElements = 0, iTGSP = 0, iComma = 0;
StreamReader mgsp = new StreamReader(master_file);
mgsp_count = 0; //initialize the elemenst count of number of
gsps stored in
//master gsp array.

//the mater_file is comma delimited and quote defined text format.
//need to read each line and extract the comma elements and
populate
//the master_array(#sites, #elements).
while (mgsp.Peek() >= 0)
{
:
:
if (iElements == 98 && rBngsp.Checked == true)
{
iTGSP = Convert.ToInt16(master_gsp[iSite, 1]);
tgsp_array[iTGSP] = "1";
worker.ReportProgress(iSite / 16);
iSite++;
i = 0;
iElements = 0;
iPlace = 0;
}
if (iElements >= 96 && rBListLDN.Checked == true)
{
if (iElements == 96)
{
master_gsp[iSite, 96] = "";
master_gsp[iSite, 97] = "";
}
if (iElements == 97)
master_gsp[iSite, 97] = "";
iTGSP = Convert.ToInt16(master_gsp[iSite, 1]);
tgsp_array[iTGSP] = "1";
worker.ReportProgress(iSite / 16);
iSite++;
i = 0;
iElements = 0;
iPlace = 0;
}
}//for (int i = 0; iSite < lcount; ++i)
if (iSite == lcount)
break;
}//while (mgsp.Peek() >= 0)
mgsp.Close();
mgsp_count = iSite;
}//private void build_master_gsparray(int lcount)
 
auldh said:
hello,

i'm having problems getting my three progressbar getting updates.

i created the backgroundworker and enabled the "WorkerReportsProgress =
true". i specified the 3 progressbars in the "private void
bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)".

the back ground worker calls a function, that function is doing construction
of a multiple collection so i want to give the user progress via the
progressbar. but i'm not getting the progressbar to show any progress.

originally i had "private void ListLDN_Start(string[] filenames,
BackgroundWorker worker, DoWorkEventArgs e)" call the three functions with
out including "BackgroundWorker worker, DoWorkEventArgs e". but even if i
continue to pass the background worker i'm still not getting updates.

i'm not understanding or finding any samples on the internet that explain or
help me conquer my problem.

what i'm i doing wrong/missing? clearly i'm doing it wrong but not
successful in finding the problem.

Well, what do you do in your ProgressChanged event handler?

I mean this only in the spirit of constructive criticism, but frankly
the code you posted is some of the most convoluted, disorganized code
I've seen in awhile. IMHO, you will definitely have an easier time
getting things to work if you get into the habit of generalizing the
code better, taking advantage of things like named constants to make the
code more maintainable, and avoiding redundancies like calling the
StreamReader.Peek() method.

Given the code you posted, it's not at all clear that your code ever
calls ReportProgress(). I mean, it could. And I could make assumptions
that it is. But the code you posted doesn't even compile, you've got
one method that uses the variable "iSite" without even having a
declaration for the variable, never mind actually updates it, and the
blocks of code that do call ReportProgress() are protected by
conditional statements having no obvious guarantee that they are ever
executed.

But, assuming your code does call ReportProgress() with the correct
values relevant for your ProgressBar instances (three of them? why?),
then obviously the problem is not even in the incomplete code you posted.

Unfortunately, lacking a concise-but-complete code example that reliably
reproduces the problem, it's not possible to figure out what might be
wrong. For a good answer, you really do need to post a code sample that
doesn't include any of the unrelated code (i.e. basically, anything
having to do with the actual work your program is doing) and yet which
still has the problem you describe. The code example must be able to be
compiled without any additional code or changes.

In the mean time, you can use Google Groups to search this newsgroup for
the text "ProgressChanged", and you'll find lots of discussions and
examples of how to use both BackgroundWorker and ProgressChanged,
including some of both together. In fact, a couple of years ago, I
wrote this example:
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/0d3b7aee7712b07e

It's a simple demonstration application, simulating multiple
simultaneous downloads, each with their own ProgressBar showing the
"progress" of the simulated download. It was actually written in
response to a somewhat more complicated question, and so may be somewhat
more complicated a code example than what you need or would like to try
to look through. But it does show how to use ProgressBar and it does
work. :)

Pete
 
thank you Peter.
i did not put the full code thought it better not to. i will check out your
example.

Peter Duniho said:
auldh said:
hello,

i'm having problems getting my three progressbar getting updates.

i created the backgroundworker and enabled the "WorkerReportsProgress =
true". i specified the 3 progressbars in the "private void
bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)".

the back ground worker calls a function, that function is doing construction
of a multiple collection so i want to give the user progress via the
progressbar. but i'm not getting the progressbar to show any progress.

originally i had "private void ListLDN_Start(string[] filenames,
BackgroundWorker worker, DoWorkEventArgs e)" call the three functions with
out including "BackgroundWorker worker, DoWorkEventArgs e". but even if i
continue to pass the background worker i'm still not getting updates.

i'm not understanding or finding any samples on the internet that explain or
help me conquer my problem.

what i'm i doing wrong/missing? clearly i'm doing it wrong but not
successful in finding the problem.

Well, what do you do in your ProgressChanged event handler?

I mean this only in the spirit of constructive criticism, but frankly
the code you posted is some of the most convoluted, disorganized code
I've seen in awhile. IMHO, you will definitely have an easier time
getting things to work if you get into the habit of generalizing the
code better, taking advantage of things like named constants to make the
code more maintainable, and avoiding redundancies like calling the
StreamReader.Peek() method.

Given the code you posted, it's not at all clear that your code ever
calls ReportProgress(). I mean, it could. And I could make assumptions
that it is. But the code you posted doesn't even compile, you've got
one method that uses the variable "iSite" without even having a
declaration for the variable, never mind actually updates it, and the
blocks of code that do call ReportProgress() are protected by
conditional statements having no obvious guarantee that they are ever
executed.

But, assuming your code does call ReportProgress() with the correct
values relevant for your ProgressBar instances (three of them? why?),
then obviously the problem is not even in the incomplete code you posted.

Unfortunately, lacking a concise-but-complete code example that reliably
reproduces the problem, it's not possible to figure out what might be
wrong. For a good answer, you really do need to post a code sample that
doesn't include any of the unrelated code (i.e. basically, anything
having to do with the actual work your program is doing) and yet which
still has the problem you describe. The code example must be able to be
compiled without any additional code or changes.

In the mean time, you can use Google Groups to search this newsgroup for
the text "ProgressChanged", and you'll find lots of discussions and
examples of how to use both BackgroundWorker and ProgressChanged,
including some of both together. In fact, a couple of years ago, I
wrote this example:
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/0d3b7aee7712b07e

It's a simple demonstration application, simulating multiple
simultaneous downloads, each with their own ProgressBar showing the
"progress" of the simulated download. It was actually written in
response to a somewhat more complicated question, and so may be somewhat
more complicated a code example than what you need or would like to try
to look through. But it does show how to use ProgressBar and it does
work. :)

Pete
.
 
Peter,
let me start with a simple question (i think) how do i call, send data to a
specific progressbar.

if i have 3 progressbars one for each specific function.
using backgroundworker.

what is the method to update a specific progressbar?
for example progressbar is associated to function1.
progressbar2 is associated to function2 and so on.
i'm assuming i have only one "backgrounworker_progresschanged" with all
three progressbars. what is needed to be identify each function to each
progressbar?



auldh said:
thank you Peter.
i did not put the full code thought it better not to. i will check out your
example.

Peter Duniho said:
auldh said:
hello,

i'm having problems getting my three progressbar getting updates.

i created the backgroundworker and enabled the "WorkerReportsProgress =
true". i specified the 3 progressbars in the "private void
bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)".

the back ground worker calls a function, that function is doing construction
of a multiple collection so i want to give the user progress via the
progressbar. but i'm not getting the progressbar to show any progress.

originally i had "private void ListLDN_Start(string[] filenames,
BackgroundWorker worker, DoWorkEventArgs e)" call the three functions with
out including "BackgroundWorker worker, DoWorkEventArgs e". but even if i
continue to pass the background worker i'm still not getting updates.

i'm not understanding or finding any samples on the internet that explain or
help me conquer my problem.

what i'm i doing wrong/missing? clearly i'm doing it wrong but not
successful in finding the problem.

Well, what do you do in your ProgressChanged event handler?

I mean this only in the spirit of constructive criticism, but frankly
the code you posted is some of the most convoluted, disorganized code
I've seen in awhile. IMHO, you will definitely have an easier time
getting things to work if you get into the habit of generalizing the
code better, taking advantage of things like named constants to make the
code more maintainable, and avoiding redundancies like calling the
StreamReader.Peek() method.

Given the code you posted, it's not at all clear that your code ever
calls ReportProgress(). I mean, it could. And I could make assumptions
that it is. But the code you posted doesn't even compile, you've got
one method that uses the variable "iSite" without even having a
declaration for the variable, never mind actually updates it, and the
blocks of code that do call ReportProgress() are protected by
conditional statements having no obvious guarantee that they are ever
executed.

But, assuming your code does call ReportProgress() with the correct
values relevant for your ProgressBar instances (three of them? why?),
then obviously the problem is not even in the incomplete code you posted.

Unfortunately, lacking a concise-but-complete code example that reliably
reproduces the problem, it's not possible to figure out what might be
wrong. For a good answer, you really do need to post a code sample that
doesn't include any of the unrelated code (i.e. basically, anything
having to do with the actual work your program is doing) and yet which
still has the problem you describe. The code example must be able to be
compiled without any additional code or changes.

In the mean time, you can use Google Groups to search this newsgroup for
the text "ProgressChanged", and you'll find lots of discussions and
examples of how to use both BackgroundWorker and ProgressChanged,
including some of both together. In fact, a couple of years ago, I
wrote this example:
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/0d3b7aee7712b07e

It's a simple demonstration application, simulating multiple
simultaneous downloads, each with their own ProgressBar showing the
"progress" of the simulated download. It was actually written in
response to a somewhat more complicated question, and so may be somewhat
more complicated a code example than what you need or would like to try
to look through. But it does show how to use ProgressBar and it does
work. :)

Pete
.
 
auldh said:
Peter,
let me start with a simple question (i think) how do i call, send data to a
specific progressbar.

if i have 3 progressbars one for each specific function.
using backgroundworker.

what is the method to update a specific progressbar?

The documentation for the ProgressBar class provides useful answers to
the question of how to update a ProgressBar. See:
http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx

As far as figuring out which ProgressBar instance to update, that
depends entirely on your own code design. Presumably, you have some
mapping from a given task to a given ProgressBar instance. So you
simply use that mapping to decide which ProgressBar to update given a task.

Again, the example I suggested shows arbitrarily many background tasks,
each with their own ProgressBar. So you can see at least one possible
approach simply by reviewing that example.
for example progressbar is associated to function1.
progressbar2 is associated to function2 and so on.
i'm assuming i have only one "backgrounworker_progresschanged" with all
three progressbars.

Why are you assuming that? One possible approach is to have a separate
event handler for each task's ProgressChanged event. But, if you insist
on using a comment event handler (which is not really a bad design), you
simply need to make sure you include enough context as part of the event
to determine which ProgressBar needs to be updated.
what is needed to be identify each function to each
progressbar?

The basic answer to that is simple: you need to know the exact instance
of ProgressBar that needs to be updated. There's no shortage of
possible solutions to that goal. You just to pick one.

Pete
 
Peter,
you know your stuff however i'm need some more insight.

i'm not up to speed on the terminology
The basic answer to that is simple: you need to know the exact instance
of ProgressBar that needs to be updated. There's no shortage of
possible solutions to that goal. You just to pick one.

i'm using the "backgroundworker" so i have all of my progressbars in one
place:
private void bgWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
progressBar2.Value = e.ProgressPercentage;
progressBar3.Value = e.ProgressPercentage;
}

i have not yet uncover samples or details on how to pass anything to
the "_ProgressChanged...". i know which progressbar goes to which
function but from my research i'm failing to specify the exact instance
for "progressbar2" in a function.

you sample code is pretty intense for me, my head is swimming on all
the information i'm viewing.

can you shove me in the a good direction?
 
auldh said:
Peter,
you know your stuff however i'm need some more insight.

i'm not up to speed on the terminology


i'm using the "backgroundworker" so i have all of my progressbars in one
place:
private void bgWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
progressBar2.Value = e.ProgressPercentage;
progressBar3.Value = e.ProgressPercentage;
}

Can you clarify? Do you _intend_ for all three ProgressBar instances to
show the same status? Or is the above simply as far as you've been able
to get with respect to updating the ProgressBar instances?

For now, I will assume the latter. If the former, you should definitely
explain why that's the behavior you want.
i have not yet uncover samples or details on how to pass anything to
the "_ProgressChanged...". i know which progressbar goes to which
function but from my research i'm failing to specify the exact instance
for "progressbar2" in a function.

From the documentation:
http://msdn.microsoft.com/en-us/library/a3zbdb1t.aspx

This is the overload for BackgroundWorker.ReportProgress() that allows
you to pass an arbitrary "user state" value, which then can be retrieved
via the UserState property of the ProgressChangedEventArgs instance
passed to your event handler.
you sample code is pretty intense for me, my head is swimming on all
the information i'm viewing.

Sorry. I realize that the example was written to illustrate something
completely different, so it's true that there is a lot of code in there
not relevant to your question. It was the best I could offer at the moment.
can you shove me in the a good direction?

I can try. :)

Assuming in your background task, you have a collection of methods used
like this:

void Outer(BackgroundWorker worker, Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar1);

Inner1(worker, items.Inner1Items);
}
}

void Inner1(BackgroundWorker worker, Inner1Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar2);

Inner2(worker, items.Inner2Items);
}
}

void Inner2(BackgroundWorker worker, Inner2Items[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar3);

// Do something useful with items
}
}

Then your event handler can look like this:

void bgWorker_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
((ProgressBar)e.UserState).Value = e.ProgressPercentage;
}

Note that the above is a very simple, rough example. A cleaner, more
maintainable design would likely encapsulate the worker code in a class
that keeps the BackgroundWorker instance reference as a member field,
rather than passing it to each method. Or even a class that inherits
BackgroundWorker and which is used as the actual BackgroundWorker
instance, for that matter (though, I prefer the former approach in most
cases).

Also, rather than tying the GUI to the background task code by
hard-coding the field names and passing those instances, you could
instead define an enumeration, and pass the values of that, letting the
GUI code map that to the appropriate ProgressBar instances.

All that together would look more like this:

enum TaskLevel
{
Outer,
Inner1,
Inner2
}

class Task
{
private BackgroundWorker _worker;

public Task(BackgroundWorker worker, Item[] items)
{
_worker = worker;

_worker.DoWork += (sender, e) =>
{
Outer(items);
};
}

public Start()
{
_worker.RunWorkerAsync();
}

private void Outer(Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Outer);

Inner1(items.Inner1Items);
}
}

private void Inner1(Inner1Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Inner1);

Inner2(items.Inner2Items);
}
}

private void Inner2(Inner2Items[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Inner2);

// Do something useful with items
}
}
}


Then in your GUI class:

class Form1 : Form
{
void bgWorker_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
ProgressBar bar = null;

switch ((TaskLevel)e.UserState)
{
case TaskLevel.Outer:
bar = progressBar1;
break;
case TaskLevel.Inner1:
bar = progressBar2;
break;
case TaskLevel.Inner2:
bar = progressBar3;
break;
}

if (bar != null)
{
bar.Value = e.ProgressPercentage;
}
}
}

Hope that helps.

Pete
 
Peter,
brilliant, absolutely.

thank you this clears things up.
For now, I will assume the latter. If the former, you should definitely
explain why that's the behavior you want.

you were correct it was the later. i just wanted each progressbar to give
the user
a graphical status of the process.

i do appreciate your help.


Peter Duniho said:
auldh said:
Peter,
you know your stuff however i'm need some more insight.

i'm not up to speed on the terminology


i'm using the "backgroundworker" so i have all of my progressbars in one
place:
private void bgWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
progressBar2.Value = e.ProgressPercentage;
progressBar3.Value = e.ProgressPercentage;
}

Can you clarify? Do you _intend_ for all three ProgressBar instances to
show the same status? Or is the above simply as far as you've been able
to get with respect to updating the ProgressBar instances?

For now, I will assume the latter. If the former, you should definitely
explain why that's the behavior you want.
i have not yet uncover samples or details on how to pass anything to
the "_ProgressChanged...". i know which progressbar goes to which
function but from my research i'm failing to specify the exact instance
for "progressbar2" in a function.

From the documentation:
http://msdn.microsoft.com/en-us/library/a3zbdb1t.aspx

This is the overload for BackgroundWorker.ReportProgress() that allows
you to pass an arbitrary "user state" value, which then can be retrieved
via the UserState property of the ProgressChangedEventArgs instance
passed to your event handler.
you sample code is pretty intense for me, my head is swimming on all
the information i'm viewing.

Sorry. I realize that the example was written to illustrate something
completely different, so it's true that there is a lot of code in there
not relevant to your question. It was the best I could offer at the moment.
can you shove me in the a good direction?

I can try. :)

Assuming in your background task, you have a collection of methods used
like this:

void Outer(BackgroundWorker worker, Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar1);

Inner1(worker, items.Inner1Items);
}
}

void Inner1(BackgroundWorker worker, Inner1Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar2);

Inner2(worker, items.Inner2Items);
}
}

void Inner2(BackgroundWorker worker, Inner2Items[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

worker.ReportProgress(progress, progressBar3);

// Do something useful with items
}
}

Then your event handler can look like this:

void bgWorker_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
((ProgressBar)e.UserState).Value = e.ProgressPercentage;
}

Note that the above is a very simple, rough example. A cleaner, more
maintainable design would likely encapsulate the worker code in a class
that keeps the BackgroundWorker instance reference as a member field,
rather than passing it to each method. Or even a class that inherits
BackgroundWorker and which is used as the actual BackgroundWorker
instance, for that matter (though, I prefer the former approach in most
cases).

Also, rather than tying the GUI to the background task code by
hard-coding the field names and passing those instances, you could
instead define an enumeration, and pass the values of that, letting the
GUI code map that to the appropriate ProgressBar instances.

All that together would look more like this:

enum TaskLevel
{
Outer,
Inner1,
Inner2
}

class Task
{
private BackgroundWorker _worker;

public Task(BackgroundWorker worker, Item[] items)
{
_worker = worker;

_worker.DoWork += (sender, e) =>
{
Outer(items);
};
}

public Start()
{
_worker.RunWorkerAsync();
}

private void Outer(Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Outer);

Inner1(items.Inner1Items);
}
}

private void Inner1(Inner1Item[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Inner1);

Inner2(items.Inner2Items);
}
}

private void Inner2(Inner2Items[] items)
{
for (int i = 0; i < items.Length; i++)
{
int progress = i * 100 / items.Length;

_worker.ReportProgress(progress, TaskLevel.Inner2);

// Do something useful with items
}
}
}


Then in your GUI class:

class Form1 : Form
{
void bgWorker_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
ProgressBar bar = null;

switch ((TaskLevel)e.UserState)
{
case TaskLevel.Outer:
bar = progressBar1;
break;
case TaskLevel.Inner1:
bar = progressBar2;
break;
case TaskLevel.Inner2:
bar = progressBar3;
break;
}

if (bar != null)
{
bar.Value = e.ProgressPercentage;
}
}
}

Hope that helps.

Pete
.
 
Back
Top