Windows窗体线程和事件-ListBox及时更新,但是progressbar经历了巨大的延迟
我们的团队正在创建一个新的招聘工作流程系统,以取代旧的工作流程系统。我的任务是将旧数据迁移到新架构中。我已经决定通过创建一个小的Windows Forms项目来做到这一点,因为架构根本不同,并且直接的TSQL脚本不是一个合适的解决方案。
完成工作的主要密封类" ImportController"声明了以下委托事件:
public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e); public static event ImportProgressEventHandler importProgressEvent;
主窗口使用新线程在该类中启动静态方法:
Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData)); dataProcessingThread.Name = "Data Importer: Data Processing Thread"; dataProcessingThread.Start(settings);
ImportProgressEvent args携带字符串消息,进度条的最大int值和当前的进度int值。 Windows窗体订阅该事件:
ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);
并使用自己的委托以这种方式响应事件:
private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax); private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e) { this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax); }
最后,进度条和列表框将更新:
private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax) { string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in items) { this.lstTasks.Items.Add(item); } if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax) { this.ImportProgressBar.Maximum = progressMax; this.ImportProgressBar.Value = currentProgress; } }
事情是ListBox似乎更新得非常快,但是进度条始终不会移动,直到批处理几乎完成为止。是什么赋予了 ?
解决方案
回答
也许我们可以尝试使用BackgroundWorker组件。它使穿线更加容易。这里的例子:
- BackgroundWorker线程和支持取消
- 在.NET 2应用程序中使用BackgroundWorker组件
- BackgroundWorker示例
回答
我们确定在所有此过程中UI线程都可以自由运行吗?也就是说,它不是在Join或者其他等待中处于阻塞状态吗?那就是我的样子。
使用BackgroundWorker的建议绝对是一个好选择,它优于尝试通过大量的Refresh / Update调用来消除问题。
而且BackgroundWorker将使用池线程,这是比创建自己的短期线程更友好的行为方式。
回答
也许不在范围之内,但是有时执行Application.DoEvents();
来使gui部分对用户输入做出反应(例如,按下状态栏对话框上的取消按钮)很有用。
回答
我们是否有机会运行Windows Vista?我已经注意到一些与工作相关的应用程序中完全相同的事情。以某种方式,进度栏"动画"时似乎会有延迟。
回答
@约翰
感谢链接。
@将要
线程池没有任何好处,因为我知道它只会产生一个线程。在对SQL Server进行读写操作时,使用线程纯粹是为了具有响应UI。这当然不是短暂的线程。
关于大锤,我们是对的。但是,事实证明,我的问题毕竟是在屏幕和椅子之间。我似乎有一个异常的数据批,其外键记录比其他批次多得多,并且恰好是在过程中尽早选择的,这意味着currentProgress在10秒钟内不会获得++的支持。
@全部
感谢所有投入,这让我开始思考,让我在代码中的其他地方查找,这导致了我的谦卑,我再次证明错误通常是人为的:)
回答
There's no gain from threadpooling as I know it will only ever spawn one thread. The use of a thread is purely to have a responsive UI while SQL Server is being pounded with reads and writes. It's certainly not a short lived thread.
好的,我对此表示感谢,并很高兴找到bug,但是我们是否看过BackgroundWorker?它几乎可以完全按照工作来做,但是是以标准化的方式(即没有我们自己的委托人)并且不需要创建新线程的,这两个都是(也许很小,但也许仍然有用)优点。