Progress Bars and Threads

M

Malenfant

I have a C# application that acts as a UI for a telecommunications
rebilling system which processes very large datasets. The entire
rebilling system is inside a single object which has a
percentageCompleted property that shows how much of the dataset has
been processed. I'd like to attach a progress bar to this property but
the moment I start processing the dataset the form locks up.

I'm sure I can achieve this using threads but so far I've had trouble
getting the threads to stop locking up the UI and even more trouble
passing the percentageCompleted property to the progressbar.

Any help would be greatly appreciated.

Regards,

Steve Green
 
M

Marc Gravell

Well, what exactly are you doing at the moment?

Note also that datasets can be lousy for bulk operations...

Anyway, you can probably do a lot with background worker...

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using (Form form = new Form())
using (ProgressBar bar = new ProgressBar())
using (BackgroundWorker worker = new BackgroundWorker())
using (Button btn = new Button())
{
// bar
bar.Dock = DockStyle.Bottom;
bar.Style = ProgressBarStyle.Continuous;
bar.Visible = false;

// button
btn.Text = "Start";
btn.Click += delegate
{
btn.Enabled = false;
bar.Visible = true;
worker.RunWorkerAsync();
};

// worker
worker.WorkerReportsProgress = true;
worker.ProgressChanged += delegate(object sender,
ProgressChangedEventArgs args)
{
bar.Value = args.ProgressPercentage;
};
worker.RunWorkerCompleted += delegate
{
btn.Enabled = true;
bar.Visible = false;
};
worker.DoWork += delegate
{
// long running operation goes here
Random rand = new Random();
int total = 1400;
for (int i = 0; i < total; i++)
{
// simulate some effort
Thread.Sleep(rand.Next(25));

// every so often, report progress
if (i % 100 == 0)
{
int percent = (100 * i) / total;
worker.ReportProgress(percent);
}
}
};

form.Controls.Add(btn);
form.Controls.Add(bar);

Application.Run(form);

}
}
}
 
M

Malenfant

At the moment the rebilling object pauses every 100 records at which
point I update the progressbar, this however doesn't work.


progressBar.Maximum = callbaseRating.total_calls;
while (callbaseRating.calls_processed < callbaseRating.total_calls)
{
//Process 100 records
callbaseRating.Rate();
progressBar.Value = callbaseRating.calls_processed;
}

I'm unfamiliar with the background workers you mentioned, I'll have a
look into it.
 
M

Marc Gravell

At the moment the rebilling object pauses every 100 records at which
point I update the progressbar, this however doesn't work.

The problem is that you are doing all the work on the UI thread - so
updated-or-not, it isn't available to paint itself because it is busy
doing your work.
I'm unfamiliar with the background workers you mentioned, I'll have a
look into it.
Looking at the code you have, it would be quite easy to port to
BackgroundWorker (using bits of my example as a template).

The other (hacky) way to do this would be to call
Application.DoEvents() after you change .Value - but in this example,
a worker thread (co-ordinated by BackgroundWorker) is an ideal fit.

Marc
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


Malenfant said:
At the moment the rebilling object pauses every 100 records at which
point I update the progressbar, this however doesn't work.
I'm unfamiliar with the background workers you mentioned, I'll have a
look into it.

You need to know how to use threads. That is key for your solution, in short
you create a background thread where the real work will be done. In the mean
time the interface (which is the original thread) is doing nothing, just
displaying the P.B. When the background thread needs to update the
interface it uses Control.Invoke (it can be ANY control in the UI) to
execute a method in the UI. How this is done is a little complicated and is
better explained somewhere else.

It's very simple in reality.
 
C

Chris Shepherd

Ignacio said:
You need to know how to use threads. That is key for your solution, in short
you create a background thread where the real work will be done. In the mean
time the interface (which is the original thread) is doing nothing, just
displaying the P.B. When the background thread needs to update the
interface it uses Control.Invoke (it can be ANY control in the UI) to
execute a method in the UI. How this is done is a little complicated and is
better explained somewhere else.

Adding to this, BackgroundWorker class (as mentioned elsewhere) has the ability
to report progress, and I believe deals with any cross-threading issues for you.

It's designed to do exactly what you are looking for.

Chris.
 

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