VB.NET - Show progressbar while running background query

I am using a background worker to perform a pretty intensive stored procedure that takes a little while.  I would like to show a marquee style progress bar while the query is running so the user knows that the application has not hung.

My background worker populates a datagridview so I get a 'Cross-thread operation not valid' error.  I invoked the method in the DoWork sub but the ui of the progress bar form does not get updated... just a ghost outline of the form and then it disappears when the bw completes.  Please let me know what I am doing wrong.

here is a snippet of what i have

Public Class frmMSSViewer
    Private connstring As String = "blah blah"
    Private bw As New BackgroundWorker

    Public Sub New()
        InitializeComponent()
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, New DoWorkEventHandler(AddressOf bw_DoWork)
        AddHandler bw.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf bw_RunWorkerCompleted)
    End Sub

    Private Sub MSSViewer_Load(sender As Object, e As EventArgs) Handles Me.Load
        PopulateOpenNames()
        If Not bw.IsBusy Then
            bw.RunWorkerAsync()
        End If
    End Sub

#Region "Background Worker"
    Delegate Sub bw_DoWork_Delegate(ByVal sender As Object, ByVal e As DoWorkEventArgs)

    Private Sub bw_DoWork(sender As Object, e As DoWorkEventArgs)
        Try
            If Me.dgvMSS.InvokeRequired Then
                Dim dlgt As New bw_DoWork_Delegate(AddressOf bw_DoWork)
                Me.Invoke(dlgt, New Object() {[sender], [e]})
            Else
                Dim ds As DataSet = SqlHelper.ExecuteDataset(connstring, "mss.uspLorealMSSResponse_Quarter", Nothing)
                dgvMSS.DataSource = ds.Tables(0).DefaultView
                dgvMSS.AutoResizeColumns()
                dgvMSS.Columns(dgvMSS.Columns.Count - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
            End If
        Catch ex As Exception
            MessageBox.Show("Error populating datagrid." & vbCrLf & ex.InnerException.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Sub bw_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
        If e.Error IsNot Nothing Then
            MessageBox.Show(e.Error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
        frmProgress.Close()
    End Sub
#End Region
End Class

Open in new window

LVL 10
FamousMortimerAsked:
Who is Participating?
 
Mike TomlinsonConnect With a Mentor Middle School Assistant TeacherCommented:
This is a common mistake.  what you've done is invoked the ENTIRE bw_DoWork() method which means everything in there is running in  the main UI thread; thus negating the whole point of using a backgroundworker in the first place.

You should let the query run on the background thread and then only invoke what needs to be updated.  A more standard approach is to use the ReportProgress() method and ProgressChanged() event to update the GUI.  In your case, though, I would simply set "e.Result" in the worker and then update everything in the RunWorkerCompleted() event like this:
    Private Sub bw_DoWork(sender As Object, e As DoWorkEventArgs)
        e.Result = SqlHelper.ExecuteDataset(connstring, "mss.uspLorealMSSResponse_Quarter", Nothing)
    End Sub

    Private Sub bw_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
        If e.Error IsNot Nothing Then
            MessageBox.Show("Error populating datagrid." & vbCrLf & e.Error.InnerException.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        ElseIf Not e.Cancelled Then
            dgvMSS.DataSource = e.Result
            dgvMSS.AutoResizeColumns()
            dgvMSS.Columns(dgvMSS.Columns.Count - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
        End If
        frmProgress.Close()
    End Sub

Open in new window


Also note that I've removed the Try/Catch in the worker as this allows the exception to be passed to RunWorkerCompleted().
0
 
FamousMortimerAuthor Commented:
Very helpful.  Thank You
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.