Hui
Hui

Reputation: 14457

The right way to implement a progressbar in C#

I'm learning winforms and I have set myself a simple goal of making a progressbar that goes from empty to full. Here's my misshapen attempt:

public partial class Form1 : Form
{
    static BackgroundWorker bw = new BackgroundWorker();

    public Form1()
    {
        InitializeComponent();
        bw.DoWork += bw_DoWork;
        bw.RunWorkerAsync();
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i=0; i<100; ++i)
        {
            progressBar1.PerformStep();
            Thread.Sleep(10);
        }
    }
}

I'm pretty sure that the Thread.Sleep() is reprehensible. How do I avoid it here?

Upvotes: 4

Views: 16239

Answers (3)

Truong Hong Thi
Truong Hong Thi

Reputation: 384

If you simply want to test updating the UI while doing a time-comsuming task, Thread.Sleep is ok. For non-trivial programs, you will always find some task to do here instead.

However, you should not update the progress bar directly inside BackgroundWorker.DoWork, as Windows requires that updating UI must be called on the UI thread, not the background one. Instead, call BackgroundWorker.ReportProgress method. Always update the UI inside BackgroundWorker.ProgressChanged event.

You couls see the example here: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

Upvotes: 1

SirViver
SirViver

Reputation: 2441

You are already doing it almost right. The BackgroundWorker has a built in mechanism for reporting progress already.

public Form1()
{
    bw1.WorkerReportsProgress = true;
    bw1.ProgressChanged += bw1_ProgressChanged;
    bw1.DoWork += bw1_DoWork;

    bw1.RunWorkerAsync();
}

private void bw1_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;

    while (workNotDone)
    {
        //Do whatever work
        worker.ReportProgress(CalculateProgressDonePercentage());
    }
}

private void bw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //This is called on GUI/main thread, so you can access the controls properly
    progressBar.Value = e.ProgressPercentage;
}

Unless of course you're just trying to animate a progress bar without actually reporting any progress, in which case you should probably just use the Marquee type that will automatically scroll a progressbar without doing anything. Or just use a background thread with Thread.Sleep().

Upvotes: 8

SLaks
SLaks

Reputation: 887453

In a background thread, there is nothing wrong with calling Thread.Sleep.
If this is a placeholder, you can safely replace that with actual work.

However, you cannot manipulate the ProgressBar (or any other control) directly from the background thread.
Instead, you should use the BackgroundWorker's built-in progress features to control the progress bar.

If you're just trying to animate a meaningless progressbasr, you should use a WinForms Timer instead of the BackgroundWorker.

Upvotes: 3

Related Questions