Threading and the Progress Bar

G

Guest

I guess it's my turn to ASK a question ;)

Briefly my problem: I am developing a Windows app that has several User
Controls. On one of these controls, I am copying/processing some rather
large binary files, so have created a second thread to do the processing.
This thread is set to be the LOWEST priority. So far so good with all that.
HOWEVER, I am trying to provide some feedback to the user (the bane of our
existence!) via a progress bar. I was attempting to update the progress bar
via code in a timer's event. When I have the timer on the the same control
as the progress bar, the application reacts the same was as it did prior to
starting the second thread, that is, it locks up the UI until the copying is
complete, AND the progress bar never gets updated.

I have a Main user control that controls the activities of the other
controls, and that has a timer on it, so I thought I would use that timer
event instead. Same reaction. UI locks up until the copy function is
complete, and the progress bar never gets updated.

Any thoughts on how I can approach this? Suggestions on what I'm doing
wrong etc?

TIA

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT
 
N

Nicholas Paldino [.NET/C# MVP]

First, you should not be setting the priority of the thread. Generally,
this is a bad idea. See the following blog entry for more information:

http://www.codinghorror.com/blog/archives/000671.html

As for updating the progress bar, why are you using a timer to indicate
when the progress bar should be updated? Why not send notifications from
your worker thread to the control with the progress bar?
 
G

Guest

Nicholas,

Thanks for the input, I'm going to try it without the timer.

As for setting the thread priorities, I also generally avoid them like the
plague, however in this case we really do need to do it.

We are getting information from an onboard computer on the aircraft in
"real" time (not really, but close enough for gov't work! ;). This process
(and one other) cannot impede the processing of that data. We really don't
care how long it takes, as long as it doesn't inhibit the main thread at all.

Thanks for the response.

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT


Nicholas Paldino said:
First, you should not be setting the priority of the thread. Generally,
this is a bad idea. See the following blog entry for more information:

http://www.codinghorror.com/blog/archives/000671.html

As for updating the progress bar, why are you using a timer to indicate
when the progress bar should be updated? Why not send notifications from
your worker thread to the control with the progress bar?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

WhiteWizard said:
I guess it's my turn to ASK a question ;)

Briefly my problem: I am developing a Windows app that has several User
Controls. On one of these controls, I am copying/processing some rather
large binary files, so have created a second thread to do the processing.
This thread is set to be the LOWEST priority. So far so good with all
that.
HOWEVER, I am trying to provide some feedback to the user (the bane of our
existence!) via a progress bar. I was attempting to update the progress
bar
via code in a timer's event. When I have the timer on the the same
control
as the progress bar, the application reacts the same was as it did prior
to
starting the second thread, that is, it locks up the UI until the copying
is
complete, AND the progress bar never gets updated.

I have a Main user control that controls the activities of the other
controls, and that has a timer on it, so I thought I would use that timer
event instead. Same reaction. UI locks up until the copy function is
complete, and the progress bar never gets updated.

Any thoughts on how I can approach this? Suggestions on what I'm doing
wrong etc?

TIA

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT
 
G

Guest

Hello,
I'm new to GUI programming in C# and so I would like to ask this question
here, because it's related to the topic. I had the same (or at least a very
similar) scenario where a worker thread does some work and a progressbar
should show the user how much of the work has already been done. But as GUI
and threads don't really like to work together without problems, I would like
to know how I can interact which the progressbar from the worker thread?

greetings

Florian

Nicholas Paldino said:
First, you should not be setting the priority of the thread. Generally,
this is a bad idea. See the following blog entry for more information:

http://www.codinghorror.com/blog/archives/000671.html

As for updating the progress bar, why are you using a timer to indicate
when the progress bar should be updated? Why not send notifications from
your worker thread to the control with the progress bar?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

WhiteWizard said:
I guess it's my turn to ASK a question ;)

Briefly my problem: I am developing a Windows app that has several User
Controls. On one of these controls, I am copying/processing some rather
large binary files, so have created a second thread to do the processing.
This thread is set to be the LOWEST priority. So far so good with all
that.
HOWEVER, I am trying to provide some feedback to the user (the bane of our
existence!) via a progress bar. I was attempting to update the progress
bar
via code in a timer's event. When I have the timer on the the same
control
as the progress bar, the application reacts the same was as it did prior
to
starting the second thread, that is, it locks up the UI until the copying
is
complete, AND the progress bar never gets updated.

I have a Main user control that controls the activities of the other
controls, and that has a timer on it, so I thought I would use that timer
event instead. Same reaction. UI locks up until the copy function is
complete, and the progress bar never gets updated.

Any thoughts on how I can approach this? Suggestions on what I'm doing
wrong etc?

TIA

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT
 
G

Guest

Here's what I came up with, and it works just great. THANKS NICHOLAS!

private void StartCopyThread()
{
copyRMMDataThread = new Thread(new ThreadStart(ProcessCopyRequest));
copyRMMDataThread.Name = "copyRMMDataThread";
copyRMMDataThread.Priority = System.Threading.ThreadPriority.Lowest;
copyRMMDataThread.Start();
}

private void ProcessCopyRequest()
{
// some initial processing

pbFileCopy.Value = 0;
pbFileCopy.Refresh();

// First we create the directory on the RMM that we are going to copy the
files to
bool dirCreated = CreateRMMCopyDirectories();
if (dirCreated)
{
try
{
// If the directories were created, we create the files...

// ...then read the trend file and process it
string filename = strAMCDirectory + @"\trend1.bin";
Stream Trend = myFlightData.ReadFlightFile(filename);
BinaryReader BinaryTrend = new BinaryReader(Trend);

while (true)
{
int NumberOfBytes = BinaryTrend.ReadInt32();
if (NumberOfBytes != 0)
{
byte[] binarySecond = BinaryTrend.ReadBytes(NumberOfBytes);
EDSCommon.TrendDataType second = ParseBinarySecond(binarySecond);
// Update the progress bar
pbFileCopy.Value = Convert.ToInt32((Trend.Position / rmmTrendSize)
* 100);
pbFileCopy.Refresh();

// continue processing
}
}

HTH

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT


Stampede said:
Hello,
I'm new to GUI programming in C# and so I would like to ask this question
here, because it's related to the topic. I had the same (or at least a very
similar) scenario where a worker thread does some work and a progressbar
should show the user how much of the work has already been done. But as GUI
and threads don't really like to work together without problems, I would like
to know how I can interact which the progressbar from the worker thread?

greetings

Florian

Nicholas Paldino said:
First, you should not be setting the priority of the thread. Generally,
this is a bad idea. See the following blog entry for more information:

http://www.codinghorror.com/blog/archives/000671.html

As for updating the progress bar, why are you using a timer to indicate
when the progress bar should be updated? Why not send notifications from
your worker thread to the control with the progress bar?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

WhiteWizard said:
I guess it's my turn to ASK a question ;)

Briefly my problem: I am developing a Windows app that has several User
Controls. On one of these controls, I am copying/processing some rather
large binary files, so have created a second thread to do the processing.
This thread is set to be the LOWEST priority. So far so good with all
that.
HOWEVER, I am trying to provide some feedback to the user (the bane of our
existence!) via a progress bar. I was attempting to update the progress
bar
via code in a timer's event. When I have the timer on the the same
control
as the progress bar, the application reacts the same was as it did prior
to
starting the second thread, that is, it locks up the UI until the copying
is
complete, AND the progress bar never gets updated.

I have a Main user control that controls the activities of the other
controls, and that has a timer on it, so I thought I would use that timer
event instead. Same reaction. UI locks up until the copy function is
complete, and the progress bar never gets updated.

Any thoughts on how I can approach this? Suggestions on what I'm doing
wrong etc?

TIA

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT
 
N

Nicholas Paldino [.NET/C# MVP]

Woah, you need to change this code big time.

What I would do is before you start the new thread, set the Value
property of your progress bar to zero.

Then, define the following delegate:

private delegate void SetProgressBarValueDelegate(int value);

And then define the following method:

private void SetProgressBarValue(int value)
{
// Set the value.
pbFileCopy.Value = value;
}

Then, wherever you have a call to "pbFileCopy.Value = ?" in your
ProcessCopyRequest method, change it to:

this.Invoke(new SetProgressBarValueDelegate(SetProgressBarValue), new
object[]{ <value> });

The reason you need to do this is that you need to make calls to update
the UI on the UI thread. The call to Invoke takes a delegate and executes
it on the UI thread.

If you are using .NET 2.0, you don't even need to declare the delegate
or the method, you could do this:

Action<int> del = delegate(int value) { pbFileCopy.Value = value; };
this.Invoke(del, new object[]{ <value> });

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

WhiteWizard said:
Here's what I came up with, and it works just great. THANKS NICHOLAS!

private void StartCopyThread()
{
copyRMMDataThread = new Thread(new ThreadStart(ProcessCopyRequest));
copyRMMDataThread.Name = "copyRMMDataThread";
copyRMMDataThread.Priority = System.Threading.ThreadPriority.Lowest;
copyRMMDataThread.Start();
}

private void ProcessCopyRequest()
{
// some initial processing

pbFileCopy.Value = 0;
pbFileCopy.Refresh();

// First we create the directory on the RMM that we are going to copy the
files to
bool dirCreated = CreateRMMCopyDirectories();
if (dirCreated)
{
try
{
// If the directories were created, we create the files...

// ...then read the trend file and process it
string filename = strAMCDirectory + @"\trend1.bin";
Stream Trend = myFlightData.ReadFlightFile(filename);
BinaryReader BinaryTrend = new BinaryReader(Trend);

while (true)
{
int NumberOfBytes = BinaryTrend.ReadInt32();
if (NumberOfBytes != 0)
{
byte[] binarySecond = BinaryTrend.ReadBytes(NumberOfBytes);
EDSCommon.TrendDataType second = ParseBinarySecond(binarySecond);
// Update the progress bar
pbFileCopy.Value = Convert.ToInt32((Trend.Position / rmmTrendSize)
* 100);
pbFileCopy.Refresh();

// continue processing
}
}

HTH

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT


Stampede said:
Hello,
I'm new to GUI programming in C# and so I would like to ask this question
here, because it's related to the topic. I had the same (or at least a
very
similar) scenario where a worker thread does some work and a progressbar
should show the user how much of the work has already been done. But as
GUI
and threads don't really like to work together without problems, I would
like
to know how I can interact which the progressbar from the worker thread?

greetings

Florian

Nicholas Paldino said:
First, you should not be setting the priority of the thread.
Generally,
this is a bad idea. See the following blog entry for more information:

http://www.codinghorror.com/blog/archives/000671.html

As for updating the progress bar, why are you using a timer to
indicate
when the progress bar should be updated? Why not send notifications
from
your worker thread to the control with the progress bar?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I guess it's my turn to ASK a question ;)

Briefly my problem: I am developing a Windows app that has several
User
Controls. On one of these controls, I am copying/processing some
rather
large binary files, so have created a second thread to do the
processing.
This thread is set to be the LOWEST priority. So far so good with
all
that.
HOWEVER, I am trying to provide some feedback to the user (the bane
of our
existence!) via a progress bar. I was attempting to update the
progress
bar
via code in a timer's event. When I have the timer on the the same
control
as the progress bar, the application reacts the same was as it did
prior
to
starting the second thread, that is, it locks up the UI until the
copying
is
complete, AND the progress bar never gets updated.

I have a Main user control that controls the activities of the other
controls, and that has a timer on it, so I thought I would use that
timer
event instead. Same reaction. UI locks up until the copy function
is
complete, and the progress bar never gets updated.

Any thoughts on how I can approach this? Suggestions on what I'm
doing
wrong etc?

TIA

WhiteWizard
aka Gandalf
MCSD.NET, MCAD, MCT
 
W

William Stacey [MVP]

With 2.0 it can be really simple.
private void button4_Click(object sender, EventArgs e)
{
int num = 0;
new Thread(
delegate()
{
while (num < 100)
{
// Do work.
num++;
Thread.Sleep(100);

// Update progress bar.
this.Invoke(
(MethodInvoker)delegate()
{
this.progressBar1.Value = num;
});
}
}).Start();
}

--
William Stacey [MVP]

|I guess it's my turn to ASK a question ;)
|
| Briefly my problem: I am developing a Windows app that has several User
| Controls. On one of these controls, I am copying/processing some rather
| large binary files, so have created a second thread to do the processing.
| This thread is set to be the LOWEST priority. So far so good with all
that.
| HOWEVER, I am trying to provide some feedback to the user (the bane of our
| existence!) via a progress bar. I was attempting to update the progress
bar
| via code in a timer's event. When I have the timer on the the same
control
| as the progress bar, the application reacts the same was as it did prior
to
| starting the second thread, that is, it locks up the UI until the copying
is
| complete, AND the progress bar never gets updated.
|
| I have a Main user control that controls the activities of the other
| controls, and that has a timer on it, so I thought I would use that timer
| event instead. Same reaction. UI locks up until the copy function is
| complete, and the progress bar never gets updated.
|
| Any thoughts on how I can approach this? Suggestions on what I'm doing
| wrong etc?
|
| TIA
|
| WhiteWizard
| aka Gandalf
| MCSD.NET, MCAD, MCT
 
J

joachim

Just a suggestion: the BackgroundWorker class comes in very handy when
doing resources-intensive stuff. I use it quite a lot and am very happy
with it.
The advantages:
1. the load is put on a seperate thread so your GUI doesn't suffer
the consequences
2. you can split your code easily into a processing part and GUI
updating parts
This would be an example:

private ProgressBar bar;
private BackgroundWorker bgWorker;

// Initialize your progressbar
bar = new ProgressBar();
bar.Value = 0;
bar.Maximum = 100;

// Initialize your backgroundworker
bgWorker = new BackgroundWorker()
bgWorker.WorkerReportsProgress = true;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
bgWorker.ProgressChanged += new
ProgressChangedEventHandler(bgWorker_ProgressChanged);


// Call to time and resources consuming code
// asynchronously
bgWorker.RunWorkerAsync();

private void bgWorker_Dowork (object sender, DoWorkEventArgs e)
{
// Her comes your actual heavy code.
// Keep threads separated, so no calls to GUI should be made.
// Instead, use the ReportProgress(int myValue) method
for (int i = 0; i < 100; i++)
{
bgWorker.ReportProgress(i);
}
}

private void bgWorker_ProgressChanged (object sender,
ProgressChangedEventArgs e)
{
// Here you can take care of the GUI
// Update your progressbar
bar.Value = e.ProgressPercentage;
}

private void bgWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
// Here you can take care of all GUI things that need resetting
// and stuff like that
bar.Value = 0;
}
 
W

William Stacey [MVP]

It is fine to use. Myself I find it easier to use delegates and Invoke as
shown. Then I am not dealing with another class and its api, and I get a
more inline feel.

--
William Stacey [MVP]

| Just a suggestion: the BackgroundWorker class comes in very handy when
| doing resources-intensive stuff. I use it quite a lot and am very happy
| with it.
| The advantages:
| 1. the load is put on a seperate thread so your GUI doesn't suffer
| the consequences
| 2. you can split your code easily into a processing part and GUI
| updating parts
| This would be an example:
|
| private ProgressBar bar;
| private BackgroundWorker bgWorker;
|
| // Initialize your progressbar
| bar = new ProgressBar();
| bar.Value = 0;
| bar.Maximum = 100;
|
| // Initialize your backgroundworker
| bgWorker = new BackgroundWorker()
| bgWorker.WorkerReportsProgress = true;
| bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
| bgWorker.RunWorkerCompleted += new
| RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
| bgWorker.ProgressChanged += new
| ProgressChangedEventHandler(bgWorker_ProgressChanged);
|
|
| // Call to time and resources consuming code
| // asynchronously
| bgWorker.RunWorkerAsync();
|
| private void bgWorker_Dowork (object sender, DoWorkEventArgs e)
| {
| // Her comes your actual heavy code.
| // Keep threads separated, so no calls to GUI should be made.
| // Instead, use the ReportProgress(int myValue) method
| for (int i = 0; i < 100; i++)
| {
| bgWorker.ReportProgress(i);
| }
| }
|
| private void bgWorker_ProgressChanged (object sender,
| ProgressChangedEventArgs e)
| {
| // Here you can take care of the GUI
| // Update your progressbar
| bar.Value = e.ProgressPercentage;
| }
|
| private void bgWorker_RunWorkerCompleted(object sender,
| RunWorkerCompletedEventArgs e)
| {
| // Here you can take care of all GUI things that need resetting
| // and stuff like that
| bar.Value = 0;
| }
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top