winforms 为什么我无法使BackgroundWorker()按预期工作?

vqlkdk9b  于 2022-11-17  发布在  其他
关注(0)|答案(1)|浏览(150)

我试图运行一个下面的代码来测试BackgroundWorker,但是它给我带来了很多问题:

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace BackgroundWorkingTest
{
    public partial class Form1 : Form
    {
        BackgroundWorker backgroundWorker1 = new BackgroundWorker();
        int counter;

        public Form1()
        {
            InitializeComponent();

            backgroundWorker1 = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
        }

        private void StartButton_Click(object sender, EventArgs e) // Start
        {
            counter = 0;
            backgroundWorker1.RunWorkerAsync();
        }

        private void CancelButton_Click(object sender, EventArgs e) // Cancel
        {
            backgroundWorker1.CancelAsync();
            progressLabel.Text = "0";
        }

        private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // DoWork
        {
            int i;

            for (i = 0; i < 123456; i++)
            {
//              Application.DoEvents();    // This line doesn't help
//              Thread.Sleep(1);           // Enable this line solve the problem

                backgroundWorker1.ReportProgress(i + 1);
                counter++;

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

        private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) // Progress
        {
            progressLabel.Text = counter.ToString();
            progressLabel.Refresh();
        }

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

**1.**例如,在BackgroundWorker1_DoWork()方法中,您可以看到以下命令:

Thread.Sleep(1);

如果我禁用它,则“取消”按钮没有响应。我单击它几次,但它没有停止进程,也没有收到“操作已取消”消息。
如果我启用它,它就会工作,但我不希望在我的线程中有任何Sleep(1)命令,因为它只会减慢进程,我不希望这样。
如果启用命令:

Application.DoEvents();

它一点帮助都没有,而且“取消”按钮在计数过程中也没有响应。

**2.**我看到的另一个问题是,如果我使用以下命令:

progressLabel.Refresh();

在ProgressChanged()事件中,会发生一些非常奇怪的事情。我可以在面板上看到它完成了计数,标签上显示:“123456”。但它花了几乎一分钟,直到它显示我的“操作完成”的消息。
如果在标签显示“123456”之后,我在ProgressChanged()方法中设置了一个断点,那么我会看到它不断进入该方法,并且e.ProgressPercentage参数一直在上升。
怎么会呢?如果我在面板上看到“123456”,它不是说流程已经完成了吗?如果已经完成了,为什么它没有马上显示“操作完成”的信息呢?

**3.**如果我删除了“progressLabel.Refresh()”行,那么在标签显示“123456”之后,我会立即收到“Operation Completed”消息,但是它不会显示0到123456之间的计数(当启用Refresh()命令时,我会看到这一点)。
**4.**另一件我不太明白的事是:

当我将代码更改为使用多个BackgroundWorkers的数组而不是仅使用一个BackgroundWorkers时:

BackgroundWorker[] backgroundWorker1 = new ....

在启用Sleep(1)的情况下,我没有收到任何错误消息,尽管所有线程都将文本设置为相同的标签,并将值写入相同的计数器。
这有意义吗?为什么我没有得到任何运行时错误,从几个BackgroundWorker线程在同一时间更新相同的标签?
非常感谢。

41zrol4v

41zrol4v1#

您报告进度的频率太高:

for (i = 0; i < 123456; i++)
{
    backgroundWorker1.ReportProgress(i + 1);

...窗口的消息循环被消息溢出,无法及时服务CancelButton_Click事件。

相关问题