C#Winform ProgressBar和BackgroundWorker

时间:2009-09-24 10:50:52

标签: c# winforms progress-bar backgroundworker

我有以下问题:

我有一个名为MainForm的表单。我在这张表格上进行了长时间的操作。

当这个长时间的操作正在进行时,我需要在MainForm之上显示另一个名为ProgressForm的操作。

ProgressForm包含一个进度条,需要在长时间操作时进行更新。

长操作完成后,应自动关闭ProgressForm。

我写了以下代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ClassLibrary
{
    public class MyClass
    {
        public static string LongOperation()
        {
            Thread.Sleep(new TimeSpan(0,0,30));

            return "HelloWorld";
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace BackgroungWorker__HelloWorld
{
    public partial class ProgressForm : Form
    {
        public ProgressForm()
        {
            InitializeComponent();
        }

        public ProgressBar ProgressBar
        {
            get { return this.progressBar1; }
            set { this.progressBar1 = value; }
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using ClassLibrary;

namespace BackgroungWorker__HelloWorld
{
    public partial class MainForm : Form
    {
        ProgressForm f = new ProgressForm();

        public MainForm()
        {
            InitializeComponent();  
        }

        int count = 0;
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (f != null)
            {
                f.ProgressBar.Value = e.ProgressPercentage;
            }

            ++count;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled) 
            {  
                MessageBox.Show("The task has been cancelled");  
            }  
            else if (e.Error != null)  
            {                  
                MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString());  
            }  
            else 
            {  
                MessageBox.Show("The task has been completed. Results: " + e.Result.ToString());  
            }
        }


        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            if (f == null)
            {
                f = new ProgressForm();
            }

            f.ShowDialog();

            //backgroundWorker1.ReportProgress(100);

            MyClass.LongOperation();

            f.Close();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();

            this.Close();
        }
    }
}

我找不到更新progressBar的方法。

我应该在哪里放置backgroundWorker1.ReportProgress(),我该怎么称呼它?

我不能在MyClass中进行任何更改,因为我不知道在我的应用程序层中完成操作会发生什么或需要多长时间。

任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:12)

一个问题是你睡了30秒。通常,您会在长时间运行的任务中的不同位置呼叫ReportProgress。因此,为了证明这一点,您可能希望将代码更改为休眠1秒,但需要30次 - 每次完成睡眠时调用ReportProgress

另一个问题是,您正在通过后台主题显示ProgressForm 。您应该在 UI 线程中启动它,但是将后台工作程序的ProgressChanged事件挂钩到它。然后,当后台工作人员报告进度时,将更新进度表单。

答案 1 :(得分:2)

ReportProgress是您必须在“工作”方法中调用的方法。 此方法将引发'ProgressChanged'事件。

在表单中,您可以将事件处理程序附加到ProgressChanged事件。在事件处理程序内部,您可以更改进度条的位置。 您还可以将事件处理程序附加到RunWorkerCompleted事件,并在该事件处理程序内部,您可以关闭包含进度条的表单。

答案 2 :(得分:2)

应该注意你需要设置

backgroundWorker1.WorkerReportsProgress = true;

如果您希望后台工作程序引发ProgressChanged事件和

backgroundWorker1.WorkerSupportsCancellation = true;

如果您希望能够取消工作线程。

正如其他人所说,在你的UI线程中运行f.ShowDialog()并使用ProgressChanged来更新ProgressWindow。

要使ProgressForm自行关闭,请在backgroundWorker1_RunWorkerCompleted中调用f.Close();这意味着长时间操作已经完成,我们可以关闭窗口。

答案 3 :(得分:0)

这里需要的是不将整个主窗体传递给类,而只是将BackgroundWorker的实例传递给它!您需要将发件人转换为后台工作者,如下所示:

private void bgWorker_DoWork(object sender DoWorkEventArgs e)
{
    // Get the BackgroundWorker that raised this event
    BackgroundWorker worker = sender as BackgroundWorker;

    // And now you just send worker to whatever class you need like so:
    bgArgs args = e.Argument as bgArgs;
    MyClass objMyClass = new MyClass();

    MyClass.MyMethod(strValue, args.Option, worker);

    // Do something based on return value.
}

然后在MyClass.MyMethod()中,您将进行进度计算,只需举起worker.ReportProgress(int percentage)事件来更新主UI表单上的进度条或其他内容!

这应该完美无缺!

查看这篇MSDN文章以获取更多详细信息,请参阅他们的Fibonacci示例,这是他们的工作,因为CalculateFibonacci是一个自定义类,它将更新发送到主窗体的UI。

有关详细信息,请参阅MSDN BackgroundWorker Class