Windows 窗体线程和事件 - 列表框会及时更新,但进度条会遇到巨大的延迟

Windows Forms Threading and Events - ListBox updates promptly but progressbar experiences huge delay

提问人:hollystyles 提问时间:8/15/2008 最后编辑:tzothollystyles 更新时间:10/16/2008 访问量:1611

问:

我们的团队正在创建一个新的招聘工作流程系统来取代旧的招聘工作流程系统。我的任务是将旧数据迁移到新架构中。我决定通过创建一个小型 Windows 窗体项目来做到这一点,因为架构完全不同,并且直接的 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 参数包含字符串消息、进度条的最大 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 似乎更新得非常快,但进度条永远不会移动,直到批处理几乎完成???什么给了 ?

Windows 多线程事件 窗体 委托

评论


答:

2赞 jfs 8/15/2008 #1

也许你可以试试 BackgroundWorker 组件。它使线程更容易。示例如下:

-1赞 Will Dean 8/15/2008 #2

您确定 UI 线程在所有这些过程中都自由运行吗?即它没有在加入或其他等待中被阻止?这就是我的样子。

使用 BackgroundWorker 的建议是一个很好的建议 - 绝对优于试图通过大量刷新/更新调用来解决问题。

BackgroundWorker 将使用池线程,这是一种比创建自己的短期线程更友好的行为方式。

0赞 Peteter 8/15/2008 #3

也许超出了范围,但有时它很有用,可以使 gui 部分对用户输入做出反应,例如按下状态栏对话框中的取消按钮。Application.DoEvents();

0赞 Patrik Svensson 8/15/2008 #4

您是否有机会运行 Windows Vista?我在一些与工作相关的应用程序中注意到了完全相同的事情。不知何故,进度条“动画化”时似乎有延迟。

0赞 hollystyles 8/15/2008 #5

@John

谢谢你的链接。

@Will

线程池没有任何好处,因为我知道它只会生成一个线程。线程的使用纯粹是为了在 SQL Server 进行读取和写入时具有响应式 UI。这当然不是一个短暂的线程。

关于大锤,你是对的。但是,事实证明,我的问题毕竟出在屏幕和椅子之间。我似乎有一批不常用的数据,它比其他批次有更多的外键记录,并且恰好在过程的早期被选中,这意味着 currentProgress 在 10 秒内没有得到 ++'d。

@All

感谢您的所有输入,它让我思考,这让我在代码中寻找其他地方,这导致了我的 ahaaa 谦卑时刻,我再次证明错误通常是人为:)

-1赞 Will Dean 8/15/2008 #6

线程池没有好处,因为 我知道它只会产生一个 线。线程的使用纯粹是 在 SQL 时具有响应式 UI 服务器正在被读取和 写。这当然不是一个短篇 活线程。

好的,我很感激,很高兴你发现了你的错误,但你看过 BackgroundWorker 吗?它几乎完全可以完成您正在做的事情,但以标准化的方式(即没有您自己的委托)并且不需要创建新线程 - 这两者都是(可能很小,但也许仍然有用)优势。