我正在尝试运行以下代码来测试 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”后立即收到“操作已完成”消息,但随后却没有t 显示 0 到 123456 之间的计数(正如我在启用 Refresh() 命令时看到的那样)。
4. 还有一点我不太明白:
当我更改代码以使用多个 BackgroundWorker 的数组而不是一个时:
BackgroundWorker[] backgroundWorker1 = new ....
启用 Sleep(1) 后,我没有收到任何错误消息,尽管所有线程都将文本设置为相同的标签,并将值写入相同的计数器。
有意义吗?从多个 BackgroundWorker 线程同时更新同一标签时,我怎么没有收到任何运行时错误?
非常感谢。
最佳答案
您过于频繁地报告进度:
for (i = 0; i < 123456; i++)
{
backgroundWorker1.ReportProgress(i + 1);
...并且窗口的消息循环被消息溢出。因此它无法及时处理 CancelButton_Click
事件。
关于c# - 为什么我不能使 BackgroundWorker() 按预期工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73561953/