如何在c#中一起使用progressbar,backgroundworker,windows form?

时间:2014-12-26 11:32:33

标签: c# forms user-interface backgroundworker

我遇到了一个问题,我正在使用Backgroundworker在进度条中显示我的工作进度。用于背景工作者的代码: -

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(200);
        for (int i = 0; i <= 100; i++)
        {
           Delegate del= new DELEGATE(simulateHeavyWork);
           this.Invoke(del);

            backgroundWorker1.ReportProgress(i);
            if (backgroundWorker1.CancellationPending)
            {
                e.Cancel = true;
                backgroundWorker1.ReportProgress(0);
                return;
            }
        }

    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        percentLabel.Text = e.ProgressPercentage.ToString() + "%";

    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            MessageBox.Show("Cancelled");
        }
        else
        {
            MessageBox.Show("Completed");
        }
    }

我在代码上创建了一个委托: -

public partial class Form1 : Form
{
    private delegate void DELEGATE();


    public Form1()
    {
        InitializeComponent();

    }
     private void simulateHeavyWork()
    {
        Thread.Sleep(100);

         ...lines of code to perform some search logs operation..
....
      }
 }

我想要实现的功能是进度条应该报告我的函数simulateHeavyWork()的进度,它实际上是使用UI线程,因为它需要从我的表单控件获取输入并更新它。

现在发生的问题是: - a)代码实际上是调用simulateHeavyWork()并给出更新ui控件和工作的输出。(注意:我在这里使用了委托来避免在ui线程上运行的错误交叉控件,因为我的函数需要使用UI控件。)

一旦完成,它就开始更新进度条,这是错误的,看起来它一次又一次地调用simulateHeavyWork,并且有睡眠间隙(100)。

请帮忙!!! 问候

2 个答案:

答案 0 :(得分:1)

user3222101,正如Andy之前所说,你正在连续运行simulateHeavyWork()。此外,通过调用Invoke,您在UI线程中运行此方法,这会在UI线程中导致额外的睡眠。基本上,Invoke使用您使用它的控件的消息循环(泵)(在这种情况下为Form1)并将您的委托放入UI线程的队列以便执行。由于Sleep()调用以及simulateHeavyWork()方法中耗时的日志操作,我认为这不是一个好习惯。

我希望,明白你的问题。我建议将耗时的日志操作与UI线程分开。不要将缓慢而枯燥的I / O操作花费在UI线程的宝贵时间上。从控件中获取值(使用BackgroundWorker中的Invoke,我将在下面解释),在BackgroundWorker中执行任何操作并更新GUI(再次使用Invoke)而不触及此类UI线程沉重的任务。

正如Andy建议的那样,你可以通过RunWorkerAsync的参数传递数据,你应该创建一个可以存储你需要的任何数据的类(因为它只接受一个参数)。但是,您可以通过使用Invoke从其他线程获取表单中的值。 Invoke 方法还会返回代理中的值(请参阅下面链接中的示例),这样您就有机会在窗体上获取控件的值。创建一个委托,该委托返回您为RunWorkerAsync创建的类型类的对象,并在BackgroundWorker线程中使用此值。请查看here中的示例。

public static string GetTextThreadSafe(this TextBox box)
{
    return GetTextBoxText(box);
}

此外,示例使用Func<...>来返回值。

通过这种方式,您可以暂停(在BackgroundWorker线程中)一段时间,然后从控件中获取值(当前值)并执行您想要的任何操作(再次在BackgroundWorker线程中)。我认为,这可以改善您的代码。

答案 1 :(得分:0)

从您的问题:“这是错误的,看起来它一次又一次地调用simulateHeavyWork与睡眠的差距(100)。”

当然是打电话。看看你的代码:

for (int i = 0; i <= 100; i++)
{
   Delegate del= new DELEGATE(simulateHeavyWork);
    this.Invoke(del);

所以你在这里打电话simulateHeavyWork 100次。由于您在Thread.Sleep(100);的正文中输入了simulateHeavyWork,因此通话之间的差距约为Sleep(100)