C# Winform ProgressBar 和 BackgroundWorker

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1470927/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:52:32  来源:igfitidea点击:

C# Winform ProgressBar and BackgroundWorker

c#winformsprogress-barbackgroundworker

提问by user366312

I have the following problem:

我有以下问题:

I have a Form named MainForm. I have a long operation to be taken place on this form.

我有一个名为 MainForm 的表单。我有一个很长的手术要在这个表格上进行。

While this long operation is going on, I need to show another from named ProgressForm on top of the MainForm.

在进行这个漫长的操作时,我需要在 MainForm 顶部显示另一个名为 ProgressForm 的操作。

ProgressForm contains a progress bar which needs to be updated while the long operation is taking place.

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

After the long operation is completed, the ProgressForm should be closed automatically.

长时间操作完成后,ProgressForm 应该会自动关闭。

I have written the following code:

我编写了以下代码:

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

I can't find a way to update the progressBar.

我找不到更新progressBar.

Where should I place backgroundWorker1.ReportProgress()and how should I call this?

backgroundWorker1.ReportProgress()应该把它放在哪里,我应该如何称呼它?

I must not make any change in MyClassbecause I don't know what would happen or how long it takes to complete the operation in this layer of my application.

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

Can anyone help me?

谁能帮我?

采纳答案by Jon Skeet

One problem is that you're sleeping for 30 seconds. Normally you'd call ReportProgressat various points within your long-running task. So to demonstrate this, you might want to change your code to sleep for 1 second, but 30 times - calling ReportProgresseach time it finishes a sleep.

一个问题是你睡了 30 秒。通常,您会ReportProgress在长期运行的任务中的各个点调用。因此,为了演示这一点,您可能希望将代码更改为休眠 1 秒,但 30 次 -ReportProgress每次完成休眠时调用。

Another problem is that you're showing your ProgressFormfromthe background thread. You should start it in the UIthread, but hook the background worker's ProgressChangedevent to it. Then when the background worker reports progress, the progress form will be updated.

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

回答by Frederik Gheysels

ReportProgress is the method which you'll have to call in your 'working' method. This method will raise the 'ProgressChanged' event.

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

In your form, you can attach an eventhandler to the ProgressChanged event. Inside that eventhandler, you can change the position of the progressbar. You can also attach an eventhandler to the RunWorkerCompleted event, and inside that eventhandler, you can close the form which contains the progressbar.

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

回答by Alastair Pitts

It should be noted you need to set

需要注意的是你需要设置

backgroundWorker1.WorkerReportsProgress = true;

if you want the background worker to raise the ProgressChanged event and

如果您希望后台工作人员引发 ProgressChanged 事件并且

backgroundWorker1.WorkerSupportsCancellation = true;

if you wish to be able to cancel the worker thread.

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

As the others have said, run the f.ShowDialog() in your UI thread and use ProgressChanged to update the ProgressWindow.

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

To get the ProgressForm to self close, in backgroundWorker1_RunWorkerCompleted, call f.Close(); This means the long operation has completed and we can close the window.

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

回答by linnx88

What is needed here is to not pass the entire main form to the class, but simply the instance of your BackgroundWorker! You need to cast the sender as Background worker like so:

这里需要的是不要将整个主窗体传递给类,而只是将 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.
}

And then in your MyClass.MyMethod()you would do the progress calculations and simply raise the worker.ReportProgress(int percentage)event to update the progress bar or whatnot on your main UI form!

然后,您MyClass.MyMethod()将进行进度计算,并简单地引发worker.ReportProgress(int percentage)事件以更新主 UI 表单上的进度条或诸如此类的内容!

This should work perfectly!

这应该可以完美运行!

Check out this MSDN article for more details, see their Fibonacci example, it's what they do since CalculateFibonacciis a custom class which sends updates to Main form's UI.

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

See MSDN BackgroundWorker Classfor more details.

有关更多详细信息,请参阅MSDN BackgroundWorker 类