Question

I have a BackgrounWorker that calls vairous methods from a custom class called ExcelOutput. The below function works, but it does not allow me to check for cancellation.

Private Sub bw_DoWork(ByVal sender As Object,
                      ByVal e As DoWorkEventArgs)

    Dim UserDump As New CurrentUserDumpInfo(Me.MainForm.ConfigForm) ' Create a new instance of the CurrentUserDumpInfo
    Dim Excel As New ExcelOutput(Me)                                ' Create a new instance of the ExcelOutput 
    Dim FirstRow As Integer = 4                                     ' The row on which the output should start
    Dim CurrentRow As Integer                                       ' The currnet row on which the output shoud continue

    '** Prepare the CurrentUserDumpInfo and the ExcelOutput *'
    Call UserDump.prepare()
    Call Excel.Prepare()

    CurrentRow = Excel.OutputGroup("General", UserDump.lstGeneralHeaders, UserDump.lstGeneralData, FirstRow)
    CurrentRow = Excel.OutputGroup("Address", UserDump.lstAddressHeaders, UserDump.lstAddressData, CurrentRow + 2)

    Call Excel.AutofitContents(4, CurrentRow)
    Call Excel.AlignCells(4, CurrentRow)
    Call Excel.StyleWorksheet()
    Call Excel.MakeSafeCopy()
    Call Excel.LockWorksheet()
    Call Excel.Finish(UserDump.CurrentUser.FullName)

End Sub

To do this, I've set each methods listed above to check for errors (using Try/Catch), and if there is an error, I set bw.WorkerSupportsCancellation = True call the bw.CancelAsync() method (you'll notice I pass Me when initiating the ExcelOutput instance, making this possible).

This method works, but to implement it fully I have to wrap every call in an If block like so, making the code very long and difficult to read (each call goes from 1 line to 6 lines) -

If bw.CancellationPending = True Then
    e.Cancel = True
    Exit Sub
Else
    CurrentRow = Excel.OutputGroup("General", UserDump.lstGeneralHeaders, UserDump.lstGeneralData, 4)
End If

Is there a better way to do this, that will both keep the code short and sweat but offer the functionality of the cancellation check? Thanks.

Update

Thanks to the answer below, here is the exact bw_DoWork() method that I am now using, which achieves exactly what I was looking for -

Private Sub bw_DoWork(ByVal sender As Object,
                      ByVal e As DoWorkEventArgs)

    Dim UserDump As New CurrentUserDumpInfo(Me.MainForm.ConfigForm) ' Create a new instance of the CurrentUserDumpInfo
    Dim Excel As New ExcelOutput(Me)                                ' Create a new instance of the ExcelOutput 
    Dim FirstRow As Integer = 4                                     ' The row on which the output should start
    Dim CurrentRow As Integer                                       ' The currnet row on which the output shoud continue

    Dim Counter As Integer = 0
    While Not bw.CancellationPending = True

        Select Case Counter

            Case 0 : Call UserDump.prepare() : Exit Select  ' Prepare the CurrentUserDumpInfo object ready for use
            Case 1 : Call Excel.Prepare() : Exit Select     ' Prepare the ExcelOutput object ready for use

            Case 2 : CurrentRow = Excel.OutputGroup("General", UserDump.lstGeneralHeaders, UserDump.lstGeneralData, FirstRow) : Exit Select
            Case 3 : CurrentRow = Excel.OutputGroup("Address", UserDump.lstAddressHeaders, UserDump.lstAddressData, CurrentRow + 2) : Exit Select
            Case 4 : CurrentRow = Excel.OutputGroup("Account", UserDump.lstAccountHeaders, UserDump.lstAccountData, CurrentRow + 2) : Exit Select
            Case 5 : CurrentRow = Excel.OutputGroup("Profile", UserDump.lstProfileHeaders, UserDump.lstProfileData, CurrentRow + 2) : Exit Select

            Case 6 : Call Excel.AutofitContents(4, CurrentRow) : Exit Select
            Case 7 : Call Excel.AlignCells(4, CurrentRow) : Exit Select
            Case 8 : Call Excel.StyleWorksheet() : Exit Select
            Case 9 : Call Excel.MakeSafeCopy() : Exit Select
            Case 10 : Call Excel.LockWorksheet() : Exit Select
            Case 11 : Call Excel.Finish(UserDump.CurrentUser.FullName) : Exit Select

            Case Else : Exit While

        End Select

        Counter += 1

    End While

    '** Check to see if the BackgroundWorker should be cancelled *'
    If bw.CancellationPending = True Then e.Cancel = True

End Sub
Was it helpful?

Solution

There's a "common" rule not to use try/catch in a DoWork event. The exception is if you want to dispose or clean up objects. If an error occurs it will be available in the RunWorkerCompleted event (e.Error).

Private Sub bw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bw.DoWork

    Dim obj As IDisposable = Nothing
    Dim [error] As Exception = Nothing

    Try
        obj = New Control()
        Throw New Exception("Simulated exception")
    Catch ex As Exception
        [error] = ex
    Finally
        If (Not obj Is Nothing) Then
            obj.Dispose()
            obj = Nothing
        End If
    End Try

    If (Not [error] Is Nothing) Then
        Throw [error]
    End If

End Sub

With that being said, you can try to do the work in a While Loop and check for cancellation after each cycle.

Private Sub bw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bw.DoWork

    Dim worker As BackgroundWorker = DirectCast(sender, BackgroundWorker)
    Dim num As Integer = Nothing
    Dim obj As IDisposable = Nothing
    Dim [error] As Exception = Nothing

    Try
        'TDOD: obj = New IDisposable ()
        num = 0
        While (Not e.Cancel)
            Select Case num
                Case 0
                    'Do somthing
                    Exit Select
                Case 1
                    'Do somthing
                    Exit Select
                Case 2
                    'Do somthing
                    Exit Select
                Case Else
                    Exit While
            End Select
            num += 1
            e.Cancel = worker.CancellationPending
        End While
    Catch ex As Exception
        [error] = ex
    Finally
        If (Not obj Is Nothing) Then
            obj.Dispose()
            obj = Nothing
        End If
    End Try

    If (Not [error] Is Nothing) Then
        Throw [error]
    ElseIf (Not e.Cancel) Then
        'TODO: e.Result = Nothing 
    End If

End Sub
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top