c# - 线程和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);
}
不要忘记订阅表单关闭事件,并检查后台工作人员是否仍然忙碌。询问操作员是否可以取消这项工作。如果不是,则取消关闭,如果可以取消,则取消后台工作,并在事件表单关闭时等待完成。
推荐阅读
- javascript - ServiceWorker 注册失败,使用 localhost
- git - 为什么 git 不跟踪我的目录?
- java - 当我将文件上传到 Vsftpd 服务器时,文件被锁定
- google-cloud-firestore - 我如何知道我的 Firestore 交易是否失败?
- html - 使字体真棒图标背景透明
- java - 日食错误:“java.lang.UnsatisfiedLinkError:org.gdal.gdal.gdalJNI.AllRegister()V”
- pygame - 检查鼠标碰撞 pygame.draw.circle()
- operating-system - 在 RTOS 中运行使用全局/静态数据的多个应用程序
- angular - Angular 2 HttpBackend 与 Http 不兼容
- r - 在 rmarkdown::render() 上从 CMD 执行 R 脚本失败