我们的团队正在创建一个新的招聘工作流程系统,以取代旧的工作流程系统。我的任务是将旧数据迁移到新架构中。我决定通过创建一个小的Windows Forms项目来做到这一点,因为架构根本不同,并且直接的TSQL脚本不是一个合适的解决方案。
完成工作的主要密封类" ImportController"声明了以下委托事件:
1 2
| public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent; |
主窗口使用新线程在该类中启动静态方法:
1 2 3
| Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name ="Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings); |
ImportProgressEvent args携带字符串消息,进度条的最大int值和当前的进度int值。 Windows窗体订阅该事件:
1
| ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent); |
并使用自己的委托以这种方式响应事件:
1 2 3 4 5 6
| 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);
} |
最后,进度条和列表框将更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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示例
@约翰
感谢您的链接。
@将
线程池没有任何好处,因为我知道它只会产生一个线程。在对SQL Server进行读写操作时,使用线程纯粹是为了具有响应UI。这当然不是短暂的线程。
关于大锤,您是对的。但是,事实证明,我的问题毕竟在屏幕和椅子之间。我似乎有一个异常的数据批,其外键记录比其他批次多得多,并且恰好是在过程的早期选择的,这意味着currentProgress在10秒钟之内不会获得++信息。
@所有
感谢您的所有投入,这让我开始思考,使我得以在代码中的其他地方查找,这导致了我的谦卑,我再次证明错误通常是人为的:)
您是否有机会运行Windows Vista?我注意到在某些与工作相关的应用程序中,情况完全相同。以某种方式,进度栏"动画"时似乎会有延迟。
可能不在范围之内,但是有时对Application.DoEvents();进行操作以使gui部分响应用户输入(例如,按下状态栏对话框上的"取消"按钮)很有用。
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?它几乎完全按照您的操作来做,但是是以标准化的方式(即没有您自己的委托人)并且不需要创建新的线程-两者都是(也许很小,但也许仍然有用)优点。
您确定在所有此过程中UI线程都可以自由运行吗?也就是说,它不是在Join或其他等待中处于阻塞状态吗?那就是我的样子。
使用BackgroundWorker的建议是一个很好的建议-绝对优于尝试通过大量刷新/更新调用来大刀阔斧地摆脱问题。
而且BackgroundWorker将使用池线程,这是比创建自己的短期线程更友好的行为方式。