Progress Bar and Background Worker
Solution 1:
You seem to have it back to front. Rather than the BackgroundWorker
handling the ProgressBar
updates, use the BGW to do the time consuming work. Then at intervals you can provide updates for the ProgressBar/Form using the built-in ReportProgress
method.
Normally, you cannot (directly) access UI controls, like a ProgressBar
, from a thread other than the one it was created on (ie the UI thread). The ReportProgress
event is raised on the original/UI thread to make basic progress reporting easy.
However, it is pretty much limited to only that. To do more, for instance post results of the long process to a ListBox
, you would use a Delegate to update the control on the other/UI thread.
The Form with the long running task
Private WithEvents bgw As New BackgroundWorker
Private frmProg As ProgForm ' progress bar form
' start up
Private Sub Button1_Click(sender ...etc
' set up
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
If frmProg Is Nothing Then ' make sure progress form is instanced
ProgForm = New frmProg
End If
If bgw.IsBusy = False Then
frmProg.Show()
bgw.RunWorkerAsync(10) ' do some important work x10
End If
End Sub
' the job that will take a while
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs)
Handles bgw.DoWork
' ToDo: with multiple workers use sender, not 'bgw'
' get the amount of work to do
Dim numToDo As Integer = CInt(e.Argument)
' important, time consuming work done here
For n As Integer = 1 To numToDo
' do the "work"
System.Threading.Thread.Sleep(100)
' post a notice, passing the percentage (raises the ProgressChanged event)
bgw.ReportProgress(Convert.ToInt32((n / numToDo) * 100)
Next
End Sub
' event raised from DoWork via ReportProgress
Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
Handles bgw.ProgressChanged
' method added on the Progress form to
' receive percentage and update the meter:
frmProg.UpdateProgress(e.ProgressPercentage)
' if the progress bar was on the same form,
' update it directly:
'MyProgBar.Value = MyProgBar.Maximum
'MyProgBar.Value = pct
End Sub
' optional event raised when the long running task is complete
Private Sub bgw_RunWorkerCompleted(sender As Object,
e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
' when all done, report that too
MessageBox.Show("Work Complete!")
End Sub
Note that normally using Thread.Sleep
freezes the UI. That doesnt happen here because it is the BackgroundWorker
not the UI thread which is put to sleep.
The Form with the progress bar:
Public Sub UpdateProgress(pct As Integer)
' ToDo: Add error checking
progress.Value = progress.Maximum
progress.Value = pct
End Sub