开发者

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, DoWorkEve开发者_如何学运维ntArgs 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?


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().


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.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜