[英]Thread and BackgroundWorker
我有一个 WinForm C# 应用程序,我想执行一些可能需要几秒钟才能完成的计算。 所以为了避免线程问题和应用程序冻结,我使用了BackgroundWorker 。 当我第一次单击按钮时,一切都很好,开始按钮变得不可见,取消按钮变为可见,应用程序没有冻结问题,进度条更改成功。 但是第二次,当我点击按钮时,几秒钟开始按钮变得不可见,取消按钮也看不见,但它必须是可见的,并且应用程序进入冻结状态,然后一切都会变好。 我不知道为什么它会起作用,因为我只需要在第一次尝试时使用。 这里是我使用的代码。
注意:我已将 BackgroundWorker 表单工具箱添加到我的表单中。
private void btnStart_Click(object sender, EventArgs e)
{
btnStart.Visible = false;
btnCancel.Visible = true;
progressBar1.Value = 0;
progressBar1.Visible = true;
backGroundWorker.RunWorkerAsync();
}
private void backGroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Calculate(backGroundWorker, e);
}
private void backGroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backGroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStart.Visible = true;
btnCancel.Visible = false;
progressBar1.Visible = false;
}
void Calculate(BackgroundWorker instance, DoWorkEventArgs e)
{
// Do Some Works
instance.ReportProgress(counter);
}
你快完成了。 您只是忘记让您的后台工作人员支持取消。 此外:您的后台工作人员不应使用后台工作人员以外的任何内容。 如果后台工作人员需要表单中的一些数据来执行任务,请在开始工作时将其作为参数传递。
使用设计器可以完成以下许多工作。 如果你愿意,你可以自己编程。 处理表单时不要忘记处理后台工作人员
BackgroundWorker backgroundWorkder = new BackgroundWorker
{
WorkerReportsProgres = true,
WorkerSupportsCancellation = true,
}
// ensure that backgroundWorker is disposed when the form is disposed:
this.Components.Add(backgroundWorker);
// alternative: react on event from closed
backgroundWorker.DoWork += OnDoBackGroundWork;
backgroundWorker.ProgressChanged += OnProgressReported;
backgroundWorker.RunWorkerCompleted += OnBackgroundWorkCompleted;
第一个事件处理程序将由 backgroundWorker 执行。 此事件处理程序不应触及表单中的任何内容。
后面的两个事件处理程序将由主线程执行。 他们可以使用表单中的项目。
private void StartBackgroundWork()
{
// TODO: enable / disable buttons; show progress bar
// if your backgroundWorker needs parameters:
MyBackgroundParameters params = new MyBackgroundParameters()
{
Text = this.textBox1.Text,
Value = this.comboBox1.SelectedIndex,
...
};
this.backgroundWorker.RunWorkerAsync(params);
}
private void CancelBackgroundwork()
{
this.backgroundWorker.CancelAsync();
}
无需检查 backgroundWorker 是否已经完成。 如果是这样,cancelAsync 不会做任何事情。 此外,如果您要检查IsBusy
,那么在您 CancelAsync 之前, backgroundWorker 可能会完成。
事件处理程序:
private void OnDoBackgroundWork(object sender, DoWorkEventArgs e)
{
// if there are several backgroundWorkers that could call this, you should check
// the sender, to determine what work should be done and which parameters are passed
BackgroundWorkder backgroundWorker = (BackgroundWorker)sender;
MyBackGroundParameters params = (MyBackGroundParameters) e.DoWorkEventArgs;
// use these params to do your calculations.
// regularly, check if cancellationpending
bool calculationFinished = false;
while (!calculationFinished && !backgroundWorker.CancellationPending)
{
// do a short part of the calculation
progress = performNextCalculationStep();
backgroundWorker.ReportProgress(...)
calculationFinished = ...
}
// if here, either calculation finished, or cancelled:
MyBackgroundResult backgroundResult;
if (calculationFinished)
{
backgroundResult = new MyBackgroundResult
{
... // fill with values if completed
};
}
else
{
// cancelled
backgroundResult = new MyBackgroundResult
{
... // fill with values if cancelled
};
}
e.Result = backgroundResult;
}
在这里,我有参数来指示结果中的计算是完成还是取消。 如果需要,您还可以返回不同的对象。 事件处理程序应该检查对象的类型以查看计算是否被取消。
private void backGroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStart.Visible = true;
btnCancel.Visible = false;
progressBar1.Visible = false;
MyBackgroundResult result = (MyBackgroundResult)e.Result;
this.ProcessResult(result);
}
不要忘记订阅表单关闭事件,并检查后台工作人员是否仍然很忙。 询问接线员是否可以取消这项工作。 如果不是,则取消关闭,如果可以取消,则取消后台工作并在关闭的事件窗体中等待完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.