因此该代码采用递增数字流的值和随机起始编号。如果start1值大于start2,我希望显示与文本框对应的行,否则为另一行。
问题是我不能停止程序,直到不满足给定的循环次数。按钮只是在植入过程中挂起。我知道发生这种情况的原因是一个循环。现在我正在尝试使用backgroundWorker停止它,但我得到了相同的结果,取消按钮挂起相同的方式。
我想使用位于backgroundWorker1_ProgressChanged内的backgroundWorker的代码。我真的不太明白这里发生了什么。也许你帮我弄清楚我做错了什么:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace XX_8_0
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var random = new Random();
var start1 = random.Next(0, 100);
var start2 = random.Next(0, 100);
var incrementor1 = start1 > 50 ? -1 : 1;
var incrementor2 = start2 > 50 ? -1 : 1;
var cV1 = start1;
var cV2 = start2;
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
textBox1.AppendText("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
textBox1.AppendText("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}
答案 0 :(得分:3)
注意:我认为您的示例可能不是BackgroundWorker
可以做的好例子。基本上你的代码只是睡了一会然后报告进度,在另一个线程中几乎没用。
backgroundWorker1_ProgressChanged
加上1000 textBox1.AppendText()
非常重,因此可能需要一些时间。
按钮只是在植入过程中挂起。我知道发生这种情况的原因是循环。
当您考虑在UI线程上执行backgroundWorker1_ProgressChanged
时,无论您在backgroundWorker1_ProgressChanged
返回后在取消上点击的次数是多少,都不会处理。所有UI处理都必须由UI线程完成。应该指出后台工作线程在此期间也被挂起,不幸的是它是代码中唯一测试取消的部分。即使ReportProgress
是异步的,您仍然需要UI线程来处理取消按钮点击事件并将工作标记为CancellationPending
。
我建议您不要在backgroundWorker1_ProgressChanged
中一次性报告,也可以考虑报告将项目添加到textBox1
作为批次。
通过这种方式,您希望充分利用您的消息泵并使您的应用程序更具响应性。
将您的backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
更改为使用批次:
var builder = new StringBuilder();
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
builder.Append("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
builder.Append("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
textbox1.AppendText(builder.ToString());
答案 1 :(得分:0)
由于你的ProgressChanged
处理程序非常忙于每ReportProgress
次调用更新UI大约1000次,它将使用所有UI线程CPU时间,并且该线程将永远无法处理取消按钮,因为它是已经太忙了。
鉴于您使用了BackgroundWorker
,您应该在ProgressChanged
处理程序中移动大部分DoWork
,并在后台线程中删除该睡眠。
方式,您使用BackgroundWorker
没有任何意义。 UI线程应该尽可能少,后台线程应该尽可能多。在你的情况下睡在后台线程没有意义,因为后台工作不依赖于已经过去的时间。
移动代码后,您需要将数据发送回UI线程。但这很容易,因为ReportProgress
的重载允许将任何.NET对象传递给UI线程(假设后台工作程序是从UI线程创建的,通常就是这种情况)。另一方面,您可以简单地将用户数据转换为适当的类型,并使用该信息将相应的文本附加到文本框中。
通过改进代码,您应该能够更快地处理这些数据。顺便说一句,StringBuilder
也应该用来构建字符串。实际上,它应该会对UI性能产生巨大影响,因为您不经常更新1000次UI文本。