当用户尝试双击按钮时,后台工作线程将启动两次。
这是一个很好的解决方法吗?
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Some processing here
Thread.Sleep(1000);
button1.Invoke((MethodInvoker)delegate { button1.Enabled= true; });
}
// Run backgroundProcess
private void button1_Click(object sender, EventArgs e)
{
this.button1.Enabled = false;
backgroundWorker1.CancelAsync();
backgroundWorker1.RunWorkerAsync();
}
您可以使用backgroundWorker1_RunWorkerCompleted
事件来启用 button1。 而不是在backgroundWorker1_DoWork
启用
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.button1.Enabled = true;
//rest of operations
}
你的代码有什么问题:
您_DoWork
启用按钮的意义较小,因为backgroundWorker1.RunWorkerAssync();
会调用_DoWork()
按钮启用,因此第二次单击也会被执行。
要使用BackgrounWorker时,你必须照顾三个基本的事情。
- DoWork:如果需要,您可以处理业务逻辑的执行和工作的取消。
- RunWorker已完成:可以处理执行后任务。在这里,你想要启用按钮,所以你应该将适当的代码写入 RunWorkerFinished 事件。
如果要在任何执行点取消后台工作进程,请处理 WorkerSupportsCancel 属性。
private void button1_Click(object sender, EventArgs e) { backgroundWorker1.WorkerSupportsCancellation = true; backgroundWorker1.DoWork += backgroundWorker1_DoWork; backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted; button1.Enabled = false; backgroundWorker1.RunWorkerAsync(); } void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { button1.Invoke((MethodInvoker)delegate { button1.Enabled = true; }); backgroundWorker1.DoWork -= backgroundWorker1_DoWork; backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted; } void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < 10; i++) { Thread.Sleep(1000); AppendTextBox( "Hit: " + i.ToString() + Environment.NewLine); if (backgroundWorker1.CancellationPending) { break; } } if (backgroundWorker1.CancellationPending) { e.Cancel = true; } } public void AppendTextBox(string value) { if (InvokeRequired) { this.Invoke(new Action<string>(AppendTextBox), new object[] { value }); return; } textBox1.Text += value; } private void button2_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync(); }
如果工人实际上正在运行,那么几乎可以肯定不是。
取消是合作的。调用CancelAsync
只是将CancellationPending
标志设置为 true。由后台辅助角色定期检查此标志并响应取消。
正在运行的工作线程到达适当的点来检查该标志、检查它并做出响应的机会,所有这些都在这两行代码之间的时间间隔内:
backgroundWorker1.CancelAsync();
backgroundWorker1.RunWorkerAsync();
非常苗条。更有可能(如果工作线程正在运行)RunWorkerAsync
会抛出InvalidOperationException
,因为工作线程仍在运行。