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,那么在取消异步之前,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);
}

不要忘记订阅表单关闭事件,并检查后台工作人员是否仍在忙。询问操作员是否可以取消此项工作。如果没有,则取消关闭,如果可以取消,则取消后台工作,并在关闭的事件表单中等待完成。

最新更新