WinForm 应用程序 UI 在长时间运行期间挂起

Posted

技术标签:

【中文标题】WinForm 应用程序 UI 在长时间运行期间挂起【英文标题】:WinForm Application UI Hangs during Long-Running Operation 【发布时间】:2019-02-10 17:35:43 【问题描述】:

我有一个 Windows 窗体应用程序 我需要使用一个 for 循环,在 2000 到 3000 左右的电话中进行大量远程调用,

在执行 for 循环时,我失去了对表单和表单控件的控制,因为它变成了一个大进程,并且有时它显示“无响应”但如果我等待很长时间它又回来了,我想我需要为此使用一些线程模型,有什么想法,我该如何继续解决这个问题?

【问题讨论】:

Application.DoEvents() 放入循环中。 @i486 - 永远不要打电话给DoEvents()。在代码中引入难以解决的错误是一种邪恶的方式。 【参考方案1】:

您需要在后台线程上执行长时间运行的操作。

有几种方法可以做到这一点。

    您可以将方法调用排队等待在线程池线程上执行(请参阅here):

    ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
    

    在 .NET 4.0 中,您可以使用 TaskFactory:

    Task.Factory.StartNew(() => YourMethod());
    

    在 .NET 4.5 及更高版本中,您可以(并且应该,而不是 TaskFactory.StartNew())使用 Task.Run()

    Task.Run(() => YourMethod());
    

    如果您需要进度更新或完成时的通知等内容,您可以使用BackgroundWorker 来更好地控制该方法。将 BackgroundWorker 控件拖到表单上,并将您的方法附加到 dowork 事件。然后在您想运行您的方法时启动工作程序。您当然可以从代码中手动创建 BackgroundWorker,只需记住完成后需要处理它。

    为您的工作创建一个全新的线程。这是最复杂的并且没有必要,除非您需要对线程进行真正细粒度的控制。如果您想了解这一点,请参阅 Thread 课程上的 MSDN 页面。

请记住,对于任何线程,您无法更新 GUI,或从后台线程更改任何 GUI 控件。如果您想在 GUI 上做任何事情,您必须使用 Invoke(和 InvokeRequired)在 GUI 线程上触发该方法。见here。

【讨论】:

【参考方案2】:
    private voidForm_Load(object sender, EventArgs e)
    
        MethodInvoker mk = delegate
        
            //your job
        ;
        mk.BeginInvoke(callbackfunction, null);
    

    private void callbackfunction(IAsyncResult res)
    
        // it will be called when your job finishes.
    

使用 MethodInvoker 是最简单的方法。

【讨论】:

【参考方案3】:

显然,您需要使用后台线程。我建议你阅读this free e-book。

【讨论】:

以上是关于WinForm 应用程序 UI 在长时间运行期间挂起的主要内容,如果未能解决你的问题,请参考以下文章

富客户端 wpf, Winform 多线程更新UI控件

在长时间运行期间泵送 Windows 消息?

在应用程序关闭期间正确关闭一个可能运行很长时间循环的线程[重复]

使用 ReSharper,如何在长时间运行的单元测试期间显示调试输出?

如何在长时间运行的服务器操作期间与用户交互(例如确认对话框)?

让 Shiny 更新 ui 并在之后运行长时间计算