关于 vb.net:Progressbar 在其他表单加载时冻结

Progressbar freezing while the other form loading

我有 3 种形式 ;

Form1 - 主窗体

Form2 - 子表单(包含进度条和计时器)

Form3 - 包含大量内容的子表单需要时间来加载(例如从网页解析数据并在表单加载事件中将其写入 Datagridview)

我需要在 form3 加载时显示 form2 并运行进度条

我在 Form1 有以下代码;

1
2
3
Me.Hide
Form2.Show()
Form3.Show()

表格 2 中的代码;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    LoadingTimer.Enabled = True
End Sub

Private Sub LoadingTimer_Tick(sender As Object, e As EventArgs) Handles LoadingTimer.Tick

    If MyProgressBar.Value <= MyProgressBar.Maximum - 1 Then
        MyProgressBar.Value += 10
    End If
    If MyProgressBar.Value = 100 Then
        LoadingTimer.Enabled = False
        Me.Close()
    End If
    If Label1.ForeColor = Color.LimeGreen Then
        Label1.ForeColor = Color.White
    Else
        Label1.ForeColor = Color.LimeGreen
    End If
End Sub
End Class

问题是Form3正在加载时进度条开始但在开始时冻结

有什么解决办法吗?


如果您是编程新手,那么这可能有点令人困惑,但答案是将代码从 Form3Load 事件处理程序推送到 Async 方法并等待它。您的 UI 冻结,因为您正在 UI 线程上同步工作。您需要明确使用辅助线程或使用 Async/Await。这:

1
2
3
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    'Do some work.
End Sub

会变成这样:

1
2
3
4
5
6
7
8
9
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Await DoWork()
End Sub

Private Async Function DoWork() As Task
    Await Task.Run(Sub()
                       'Do some work.
                   End Sub).ConfigureAwait(False)
End Function

实际上,这可能比必要的更复杂,这应该可以正常工作:

1
2
3
4
5
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Await Task.Run(Sub()
                       'Do some work.
                   End Sub).ConfigureAwait(False)
End Sub

重新阅读您的问题后,您可能需要做的是让您的异步方法成为一个函数,该函数从网页或其他任何地方检索和返回数据,然后您将这些数据同步加载到您的 DataGridView 中,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
Private Async Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    DataGridView1.DataSource = Await GetDataAsync()
End Sub

Private Async Function GetDataAsync() As Task(Of DataTable)
    Return Await Task.Run(Function()
                              Dim table As New DataTable

                              'Populate table here.

                              Return table
                          End Function).ConfigureAwait(False)
End Function

所以 GetDataAsync 方法返回一个 Task(Of DataTable),即异步执行返回 DataTable 的函数的 Task。在 Load 事件处理程序中,您调用该方法并等待 Task,这意味着您的代码将等到 Task 执行并返回其数据,但不会像同步调用那样阻塞 UI 线程。同步等价物是这样的:

1
2
3
4
5
6
7
8
9
10
11
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    DataGridView1.DataSource = GetData()
End Sub

Private Function GetData() As DataTable
    Dim table As New DataTable

    'Populate table here.

    Return table
End Function


尝试使过程异步,据我了解,计时器滴答已经是异步的,但是在 form1 中,您可以使用可以在任务中包含该代码

1
2
3
Me.Hide
Task.Run(Function() Form2.Show())
Form3.Show()

自从我开始在 c# 上编程以来,我从未在 vb.net 上达到过这么远,但这应该可以解决问题