Windows窗体线程和事件-ListBox及时更新,但是progressbar经历了巨大的延迟

时间:2020-03-05 18:39:50  来源:igfitidea点击:

我们的团队正在创建一个新的招聘工作流程系统,以取代旧的工作流程系统。我的任务是将旧数据迁移到新架构中。我已经决定通过创建一个小的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?它几乎可以完全按照工作来做,但是是以标准化的方式(即没有我们自己的委托人)并且不需要创建新线程的,这两个都是(也许很小,但也许仍然有用)优点。