【发布时间】:2013-11-26 09:31:12
【问题描述】:
我有一个程序 (WPF),它每隔 10 秒执行一次测量。测量时间各不相同,因此可能需要 1 秒或 3 秒,例如:
|o........|..o......|o........|...o.....|o..
|...measurement start o...measurement finished
我想要一个 ProgressBar,它显示下一个测量任务的开始时间。 此外,每次测量完成时,我都会将值添加到图形元素中以显示它们。
现在问题来了:我有一个 BackgroundWorker,它检查是否是时候执行测量了。如果时间到了,BackgroundWorker 会启动其他执行测量的 Worker。
现在我刚刚实现了使用“bw.ReportProgress(0)”完成测量时显示数据的功能(0 是一个没有用的虚拟值):
private void measure_interval_worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
DateTime timeToMeasure = DateTime.Now;
Boolean varsSaved = true; //if vars are saved
while (!measure_interval_worker.CancellationPending)
{
if (activeDevices.Count == 0 && varsSaved == false) //Devives are finished and vars aren't save yet
{
bw.ReportProgress(0); //In ProgressChanged the values are displayed
varsSaved = true;
}
if (DateTime.Now >= timeToMeasure && activeDevices.Count == 0) //If its time to measure and all devices are done with measurement
{
timeToMeasure = DateTime.Now + measure_gap; //Next time to measure
measure_workers = new List<BackgroundWorker>(); //Deleting the "old" workers?
foreach (var dev in devices)
{
//Add Key
varsSaved = false;
activeDevices.Add(dev.Key);
//And start worker
measure_workers.Add(new BackgroundWorker());
measure_workers[measure_workers.Count - 1].DoWork += measure_perform_DoWork;
measure_workers[measure_workers.Count - 1].RunWorkerAsync(dev.Key);
}
}
}
}
activeDevices 只是一个列表,其中 measure_workers 删除他们的名字,如果他们完成了,那么 activeDevices.Count == 0 意味着所有的测量任务都完成了。
我现在尝试为进度条使用调度程序,例如:
this.Dispatcher.BeginInvoke((Action)delegate()
{
pbProgress.Value = (int)((timeToMeasure - DateTime.Now).TotalSeconds/ measure_gap.TotalSeconds * 100);
});
(将它放在 measure_interval_worker while 循环内)但现在如果我启动 measure_interval_worker,GUI 会冻结。
那我该如何解决呢?
我可以将 ReportProgress 用于 ProgressBar,但是我在显示数据时遇到了同样的问题,因为我不知道值何时可以显示。
【问题讨论】:
-
在调试器中按“停止”并分析程序阻塞 GUI 的调用堆栈。整个程序是不是死锁了?
-
在当前表格中,没有保证 measure_workers 是完整的。我同意其他 cmets 不要在 BackgroundWorker 中使用 BackgroundWorker。我会在里面使用 BlockingCollection。如果 CancellationPending 我会设置 e.Cancel = true;
标签: c# wpf backgroundworker