i950
asked on
backgroundWorker.. DoWork and ProgressChanged
Hello,
I using a backgroundWorker to execute a time consuming operation and print the result as they come an a listView. I'm basically doing something similar to the following:
private void backgroundWorker1_DoWork(o bject sender, DoWorkEventArgs e)
{
while (condition)
{
if (backgroundWorker1.Cancell ationPendi ng)
{
e.Cancel = true;
}
else
{
// code... bla bla bla
globalItemName = someVar;
Console.WriteLine("In DoWork");
backgroundWorker1.ReportPr ogress(1);
}
}
}
private void backgroundWorker1_Progress Changed(ob ject sender, ProgressChangedEventArgs e)
{
Console.WriteLine("In ProgressChanged");
listView1.Items.Add(global ItemName);
progressBar1.Value = e.ProgressPercentage;
}
It's not working, all the 'In DoWork' is printed in the output window first then 'In ProgressChanged' is printed after.
What's wrong?
Thanks.
I using a backgroundWorker to execute a time consuming operation and print the result as they come an a listView. I'm basically doing something similar to the following:
private void backgroundWorker1_DoWork(o
{
while (condition)
{
if (backgroundWorker1.Cancell
{
e.Cancel = true;
}
else
{
// code... bla bla bla
globalItemName = someVar;
Console.WriteLine("In DoWork");
backgroundWorker1.ReportPr
}
}
}
private void backgroundWorker1_Progress
{
Console.WriteLine("In ProgressChanged");
listView1.Items.Add(global
progressBar1.Value = e.ProgressPercentage;
}
It's not working, all the 'In DoWork' is printed in the output window first then 'In ProgressChanged' is printed after.
What's wrong?
Thanks.
ASKER
Hi Alex,
I'm getting:
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Not:
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
I'm getting:
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Not:
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
I made small test and reproduced this behavour. This means, BackgroundWorker.ReportPro gress invokes ProgressChanged event asynchronously. Line
backgroundWorker1.ReportPr ogress(1);
is executed, and worker thread code continues immediately, without waiting for ProgressChanged function. Computer makes thread switch with some time interval. In your case, backgroundWorker1_DoWork function is executed in one time interval scheduled to this thread. When thread exits, main thread is activated and executes all ProgressChanged events from event queue.
Make small change:
backgroundWorker1.ReportPr ogress(1);
System.Threading.Thread.Sl eep(0);
Now you can see expected result. Sleep(0) causes thread context switch, and ProgressChanged is called immediately.
However, Sleep(0) is added only for test, remove it. Asynchronous behavior of BackgroundWorker is absolutely OK, this is the way multithreading must work.
backgroundWorker1.ReportPr
is executed, and worker thread code continues immediately, without waiting for ProgressChanged function. Computer makes thread switch with some time interval. In your case, backgroundWorker1_DoWork function is executed in one time interval scheduled to this thread. When thread exits, main thread is activated and executes all ProgressChanged events from event queue.
Make small change:
backgroundWorker1.ReportPr
System.Threading.Thread.Sl
Now you can see expected result. Sleep(0) causes thread context switch, and ProgressChanged is called immediately.
However, Sleep(0) is added only for test, remove it. Asynchronous behavior of BackgroundWorker is absolutely OK, this is the way multithreading must work.
BTW, you can add more code to backgroundWorker1_DoWork to make it more time consuming. This this case output will look like this (without Sleep):
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Every thread executes its work in time interval given to this thread by operating system. This is exactly what we expect from parellel asynchronous execution.
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In DoWork");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Console.WriteLine("In ProgressChanged");
Every thread executes its work in time interval given to this thread by operating system. This is exactly what we expect from parellel asynchronous execution.
ASKER
Ahaaaa... it's clear now.
So my whole idea to update the UI in ProgressChanged not going to work as expected. What I'm doing is declaring a global variable for the listView item text and I assigning this variable in DoWork then I call ReportProgress and in ReportProgress I use the global variable to get the list view item name, which may or may not be changed!!!!!
What's the correct way to update the UI in this case?
So my whole idea to update the UI in ProgressChanged not going to work as expected. What I'm doing is declaring a global variable for the listView item text and I assigning this variable in DoWork then I call ReportProgress and in ReportProgress I use the global variable to get the list view item name, which may or may not be changed!!!!!
What's the correct way to update the UI in this case?
Correct way is using BackgroundWorker.ReportPro gress Method (Int32, Object) overload. It allows to add instance of any class or primitive type (like string) as parameter.
backgroundWorker1.ReportPr ogress(1, someVar);
private void backgroundWorker1_Progress Changed(ob ject sender, ProgressChangedEventArgs e)
{
string s = (string)e.UserState;
...
}
backgroundWorker1.ReportPr
private void backgroundWorker1_Progress
{
string s = (string)e.UserState;
...
}
ASKER
It worked! Thanks!
Just one more thing...
How can I pass several variables (integers and strings) to ReportProgress?
Just one more thing...
How can I pass several variables (integers and strings) to ReportProgress?
You need to define your own class which contains all these variables, and pass instance of this class as parameter.
BackgroundWorkerData d = new BackgroundWorkerData(); // your class
d.name = somevar;
d.number1 = ...; // fill with any data
backgroundWorker1.ReportPr ogress(1, d);
private void backgroundWorker1_Progress Changed(ob ject sender, ProgressChangedEventArgs e)
{
BackgroundWorkerData d = (BackgroundWorkerData)e.Us erState;
// read data here
...
}
BackgroundWorkerData d = new BackgroundWorkerData(); // your class
d.name = somevar;
d.number1 = ...; // fill with any data
backgroundWorker1.ReportPr
private void backgroundWorker1_Progress
{
BackgroundWorkerData d = (BackgroundWorkerData)e.Us
// read data here
...
}
ASKER
Is there any performance overhead when initiating many BackgroundWorkerData here:
BackgroundWorkerData d = new BackgroundWorkerData(); // your class
d.name = somevar;
d.number1 = ...; // fill with any data
I'll be using it in a loop that may be repeated several thousand times.
BackgroundWorkerData d = new BackgroundWorkerData(); // your class
d.name = somevar;
d.number1 = ...; // fill with any data
I'll be using it in a loop that may be repeated several thousand times.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This is exactly what is written in your code:
Console.WriteLine("In DoWork");
backgroundWorker1.ReportPr
What is the problem exactly?