我正在试图找出处理单击按钮点击触发的后台工作人员的最佳方法。我用3个单选按钮和一个标签创建了一个非常简单的表单。每个单选按钮共享相同的事件radioButton_CheckedChanged。如果事件完成,那么我将标签更新为“完成”。如果在事件完成之前单击另一个单选按钮,则将标签更新为已取消。下面是我在这个快速示例中编写的代码。尽管应用程序倾向于按预期运行,但我关注的是使用Application.DoEvents。我有什么替代方案。出于显而易见的原因,我在IsBusy时无法入睡。我是否认为这一切都错了,或者有更好的方法吗? 谢谢,poco
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
if (rb.Checked)
{
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy)
Application.DoEvents();
}
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 0; i < 100 && !worker.CancellationPending; ++i)
Thread.Sleep(1);
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
label1.Text = "Canceled";
else
label1.Text = "Complete";
}
答案 0 :(得分:7)
您应该将BackgroundWorker完成时必须运行的代码移动到RunWorkerCompleted hander中。在伪代码中:
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
// ...
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
addJobToQueue(); // Don't wait here, just store what needs to be executed.
} else {
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) {
label1.Text = "Canceled";
}
else {
label1.Text = "Complete";
}
// We've finished! See if there is more to do...
if (thereIsAnotherJobInTheQueue())
{
startAnotherBackgroundWorkerTask();
}
}
答案 1 :(得分:0)
DoEvents
不应该如此随便。有更好的方法。其中一个非常好的是described here in SO。这个答案可能最适合你。
因此,您的解决方案变为:
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
if (rb.Checked)
{
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 0; i < 100 && !worker.CancellationPending; ++i)
Thread.Sleep(1);
if (worker.CancellationPending)
{
e.Cancel = true;
}
_resetEvent.Set();
}