在C#中实现进度条的正确方法

时间:2011-06-01 16:44:38

标签: c# winforms multithreading backgroundworker

我正在学习winforms,我为自己设定了一个简单的目标,即制作一个从空到满的进度条。这是我的畸形尝试:

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);
        }
    }
}

我很确定Thread.Sleep()应该受到谴责。我怎么在这里避免它?

3 个答案:

答案 0 :(得分:7)

你已经做得差不多了。 BackgroundWorker具有用于报告进度的内置机制。

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;
}

除非您当然只是尝试动画进度条而不实际报告任何进度,在这种情况下您应该只使用Marquee类型,它会自动滚动进度条而不做任何事情。或者只使用Thread.Sleep()的后台主题。

答案 1 :(得分:3)

在后台主题中,调用Thread.Sleep没有任何问题 如果这是占位符,您可以安全地将其替换为实际工作。

但是,您无法直接从后台线程操作ProgressBar(或任何其他控件) 相反,您应该使用BackgroundWorker的内置进度功能来控制进度条。

如果您只想尝试为无意义的progressbasr设置动画,则应使用WinForms Timer代替BackgroundWorker

答案 2 :(得分:1)

如果您只是想在执行耗时的任务时测试更新UI,Thread.Sleep就可以了。对于非平凡的程序,你总会在这里找到一些任务。

但是,您不应直接在BackgroundWorker.DoWork内更新进度条,因为Windows要求必须在UI线程上调用更新UI,而不是后台线程。相反,请调用BackgroundWorker.ReportProgress方法。始终更新BackgroundWorker.ProgressChanged事件内的用户界面。

你可以看到这里的例子:http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx