vb.nettimerprogress-barform-load

Progressbar freezing while the other form loading


I have 3 form ;

Form1 - Main Form

Form2 - Sub form ( contains progress bar and timer)

Form3 - Sub form with heavy contains which takes time for loading ( like parsing data from webpage and writing it to Datagridview at form load event)

I need to show form2 with a progress bar running while form3 is loading

I have following codes at Form1 ;

Me.Hide
Form2.Show()
Form3.Show()

codes from Form 2 ;

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

The problem is progress bar starting but freezing at the beginning while Form3 is loading

Any idea for solution?


Solution

  • If you're new to programming then this may be a bit confusing but the answer is to push the code from the Load event handler of Form3 into an Async method and await it. Your UI freezes because you're doing work synchronously on the UI thread. You need to either use a secondary thread explicitly or use Async/Await. This:

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

    would become this:

    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
    

    Actually, that's probably more complex than necessary and this should work fine:

    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
    

    Having reread your question, what you probably need to do is have your async method be a function that retrieves and returns the data from the web page or whatever and then you load that data into your DataGridView synchronously afterwards, e.g.

    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
    

    So the GetDataAsync method returns a Task(Of DataTable), i.e. a Task that asynchronously executes a function that returns a DataTable. In the Load event handler, you call that method and await the Task, which means that your code will wait until the Task has executed and returned its data but without blocking the UI thread as a synchronous call would do. The synchronous equivalent would be this:

    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