【发布时间】:2015-03-20 10:35:08
【问题描述】:
我有一个主要的 UI 来做一些耗时的工作。当它正在执行时,我想打开第二个带有进度条(选框样式)的表单以指示“正在处理它”。
我看到有人把耗时的任务放在BackgroundWorker,但是,我想在主 UI 线程中运行。
耗时任务将在MainForm中执行。我想为各种进程重用进度条,所以我正在编写第二个表单ProgressBarForm,其中包含BackgroundWorker,它将在显示进度条的同时启动_mainWork,并将停止并关闭ProgressBarForm 当_mainWork 完成时。
因为表单是模态的,我正在考虑在BackgroundWorker 中显示ProgressBarForm,以免阻止MainForm。
请注意,我不是在BackgroundWorker 中运行mainForm。我的 backgroundWorker 只是显示表单并可能报告一个计时器。
public partial class ProgressBarFom : UControl
{
public delegate void MainWork();
private MainWork _mainWork;
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//progressBar.Hide();
this.OnClose(sender, e);
//
backgroundWorker.Dispose();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//show this ProgressBarForm
this.ShowDialog();
//stop backgroundWorker
//calling this.Close() in RunWorkerComplete
if (backgroundWorker.CancellationPending == true)
{
e.Cancel = true;
return;
}
}
public void CallProgressBar(object sender, EventArgs e)
{
//progressBar.Show();
backgroundWorker.RunWorkerAsync();
_mainWork();
if (backgroundWorker.IsBusy)
backgroundWorker.CancelAsync();
}
}
在 MainForm 中,我传递 mainwork 并调用 ExecWithProgressBar
private void ExecWithProgressBar()
{
ProgressBarFom .MainWork mainWork = new ProgressBarFom .MainWork(ProgressBarMainWork);
ProgressBarFom prBar = new ProgressBarFom (mainWork);
prBar.CallProgressBar(null, null);
}
遇到的一些问题
在 DoWork 内部,也会出现同样的模式问题。 ShowDialog() 将阻塞线程,因此我永远不会检查 CancellationPending 来关闭 ProgressBarForm。
ProgressBarForm 启动晚于 mainWork。我想当我调用 CallProgressBar 时,backgroundWorker 应该在我的 mainWork 之前启动。
在 RunWorkerComplete 中是否需要 worker.Dispose()?
在 Worker 中运行 mainWork 会更好吗?为什么?我决定让主线程运行这个以不干扰正常流程,主线程中的内容将保留在主线程中,进度条就像一个插件。如果我们把它带到工人那里,我们是否需要另一个线程来获取进度条本身?
【问题讨论】:
-
“我看到有人把耗时的任务放在BackgroundWorker中,但是我想在主UI线程中运行” -- 为什么?为什么要拒绝经验丰富的程序员的好建议和 .NET API 的预期设计?只要以正确的方式去做。不仅有更好的资源可以向您解释如何以正确的方式进行操作,而且您的程序只会更好地工作。与 API 抗争无疑是一种让您头疼的方法和非常糟糕的代码。
-
我尝试将 _mainWork 放在 backgroundWorker 中,这会带来问题。我猜这是因为 _mainWork 使用了主线程中的一些东西。您建议如何克服这一点?
-
BackgroundWorker及其后继者Task和Progress<T>都不是灵丹妙药。您仍然可以做错并犯错误。但问题是:有 很多 在线资源可以帮助那些做错和犯错的人学习如何正确和不犯错误地做事。很少有在线资源旨在帮助人们成功地做错事,而且很少有人愿意努力创建此类资源。如果您在让BackgroundWorker工作时遇到问题,请寻求帮助以正确处理。你目前的做法注定要失败。 -
谢谢彼得。我确实做了一些功课,不幸的是网上的例子和教程往往停留在“//模拟一些耗时的任务:DoWork{System.Threading.Thread.Sleep(5000);}”你能详细说明如何在后台工作人员中正确调用_mainwork ?它会破坏我使用工作线程但反过来要求主线程完成工作的目的吗?我希望这个进度条表单可以重复使用,它可以与我输入的任何方法一起运行。这就是我尝试将 _mainWork 输入到 BackgroundWorker 的原因。
-
“它会破坏我使用工作线程但反过来要求主线程完成工作的目的” - 是的。 “我希望这个进度条表单可以重复使用”——就像
ProgressBar控件可以重复使用一样,任何其他进度 UI 实现也可以重复使用。至于详细说明“如何在后台工作人员中调用_mainwork”,如果您尝试一下,效果会更好,然后发布一个问题,在其中解释该尝试并描述您的文档和教程已经使用过,并寻求帮助。否则,答案会变得过于宽泛。
标签: c# multithreading modal-dialog progress-bar progressdialog