首页 > 解决方案 > 如何在 VB.NET 表单中处理长时间运行的任务?

问题描述

我目前正在开发一个 VB.NET 表单,该表单根据 Excel 文件和表单询问的一些额外数据(项目名称、客户名称、使用 SQL ......)自动创建 Word 文档。

此过程运行良好,大约需要 1 或 2 分钟才能完成。问题是我所有的脚本都在ButtonGenerate.ClickHandler 中。因此,当按下“生成”按钮时,表单窗口会变砖,无法取消...

它不应该在 Click 处理程序中。为那个长任务打开一个新线程似乎更好。但是多线程对我来说不是很熟悉。我尝试使用启动脚本

ThreadPool.QueueUserWorkItem(...

但是我的 Generate Sub 设置标签并在主窗体中更新进度条,所以除非我使用,否则我不会工作

Me.Invoke(New MethodInvoker(Sub()
    label.Text = "..."
    ProgressBar.Value = 10
    ' ...
End Sub)

每次我需要更新表单上的某些内容时,我什至无法使用该按钮检索任何新的按钮(取消按钮会很好)。

这基本上是我的代码:

Public Class TestFichesAutomation

Private Sub BtnGenerate_Click(sender As Object, e As EventArgs) Handles BtnGenerate.Click
    System.Threading.ThreadPool.QueueUserWorkItem(Sub() Generate())
End Sub

Public Sub Generate()
    ' Check user options, retrieve Excel Data, SQL, Fill in custom classes, create Word docs (~ 1 minute)
End Sub


那么您将如何处理该脚本?线程甚至是一个好的解决方案吗?

标签: vb.netmultithreadingwinforms

解决方案


非常感谢您的帮助^^和有用的文档。

我的应用程序现在打开一个新线程并使用 2 个自定义类来充当缓冲区:

Private Async Sub Btn_Click(sender As Object, e As EventArgs) Handles Btn.Click
     myProgress = New Progress
    ' a custom class just for the UI with the current task, current SQL connection status and progress value in %

    _Options.ProjectName = TextBoxProjectName.Text
    _Options.CustomerName = TextBoxCustomerName.Text
    ...
    ' Fill in a custom "_Options" private class to act as a buffer between the 2 thread (the user choices)       

    Loading = New Loading()
    Me.Visible = False
    Loading.Show() ' Show the Loading window (a ProgressBar and a label : inputLine)

    Task.Run(Function() Generate(Progress, _Options))
    Me.Visible = True
End Sub


Public Async Function Generate(ByVal myProgress As Progress, ByVal Options As Options) As Task(Of Boolean)
    ' DO THE LONG JOB and sometimes update the UI :
    myProgress.LoadingValue = 50 ' %
    myProgress.CurrentTask= "SQL query : " & ...
    Me.Invoke(New MethodInvoker(Sub() UpdateLoading()))
    ' Check if the task has been cancelled ("Cancelled" is changed by a passvalue from the Loading window):
    If myProgress.Cancelled = True Then ...
    ' Continue ...
End Function


Public Shared Sub UpdateLoading()
    MyForm.Loading.ProgressBar.Value = myProgress.LoadingValue
    MyForm.Loading.inputLine.Text = myProgress.CurrentTask
    ' ...
End Sub

推荐阅读