Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backgroundworker CancelAsync() won't work

I am trying to cancel my Backgroundworker with WorkerClass.bw.CancelAsync(). But it wont work at all.

//edit! I posted the full Code here. May this will help. Okay, i added some Msgboxes to know if the Worker is still busy and the wired thing is, that i get a false while the worker is doing things!?!?

Public Class Form1

Private Sub btn_start_click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_start.Click
        Dim WorkerClass As New BGWClass
        WorkerClass.bw.WorkerSupportsCancellation = True
        WorkerClass.bw.WorkerReportsProgress = True
        If btn_start.Text = "Start" Then
            btn_start.Image = My.Resources.Resources.gem_remove
            btn_add_addy.Enabled = False
            btn_start.Text = "Stop"
            WorkerClass.Start()
            WorkerClass.bw.RunWorkerAsync()
            MsgBox(WorkerClass.bw.IsBusy & " " & WorkerClass.bw.WorkerSupportsCancellation)
        Else
            btn_start.Image = My.Resources.Resources.error_fuck
            btn_add_addy.Enabled = True
            btn_start.Enabled = False
            MsgBox(WorkerClass.bw.IsBusy & " " & WorkerClass.bw.WorkerSupportsCancellation)
            WorkerClass.bw.CancelAsync()
        End If
    End Sub
End Class

Public Class BGWClass
    Public bw As BackgroundWorker = New BackgroundWorker

    Sub Start()
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.ProgressChanged, AddressOf bw_ProgressChanged
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
    End Sub

    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
         For x As Integer = 1 To 15
            If bw.CancellationPending Then
                e.Cancel = True
                Exit Sub
            End If
            bw.ReportProgress(x)
            Threading.Thread.Sleep(1000)
        Next
    End Sub

    Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs)
        Dim myObject As Object = e.UserState
        Form1.Prgs_error.Text = "- Error: " + e.ProgressPercentage.ToString
    End Sub

    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
        '...
    End Sub
End Class
like image 685
Ponch0 Avatar asked Mar 23 '23 17:03

Ponch0


2 Answers

I think your problem is that you are only evaluating CancellationPending once, at the start of your bw_DoWork method. Since there's not really a way to cancel the BackgroundWorker before it starts, CancellationPending will always be false and will never interrupt the work. The BackgroundWorker doesn't use some magic to take over the program counter when you call CancelAsync.

In order for this to work, the core logic of your DoWork method will have to be implemented in a way that allows for the frequent polling of CancellationPending so that the code will know exactly when to exit out of what it's doing. You will need to go from this:

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

    If bw.CancellationPending = True Then
        e.Cancel = True
    Else
        'do stuff here
    End If

End Sub

To something more like this:

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

    Dim workIsCompleted As Boolean = False
    While (Not bw.CancellationPending) AndAlso (Not workIsCompleted) Then

        ' Do stuff here, but incrementally so that the while loop can
        ' periodically check to see if CancelAsync has been called.
        ' Also, be sure to set workIsCompleted = True when the work is done.
        ' Otherwise, you will just spin forever until someone cancels it
        ' (Which may or may not be a bad thing, depending on your requirements)

    End While

End Sub
like image 168
mclark1129 Avatar answered Mar 26 '23 08:03

mclark1129


Here is the basic model of a BackgroundWorker. Is this how yours look.

Dim WithEvents worker As New System.ComponentModel.BackgroundWorker

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'start
    If Not worker.IsBusy Then
        worker.WorkerReportsProgress = True
        worker.WorkerSupportsCancellation = True
        worker.RunWorkerAsync()
    End If
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    'cancel
    If worker.IsBusy AndAlso worker.WorkerSupportsCancellation Then
        worker.CancelAsync()
    End If
End Sub

Private Sub foo_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
    For x As Integer = 1 To 15
        If worker.CancellationPending Then
            e.Cancel = True
            Exit For
        End If
        worker.ReportProgress(x)
        Threading.Thread.Sleep(1000)
    Next
End Sub

Private Sub foo_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles worker.ProgressChanged
    Label1.Text = e.ProgressPercentage.ToString
End Sub

Private Sub foo_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
    If e.Cancelled Then
        Label1.Text = "canceled"
    ElseIf Not IsNothing(e.Error) Then
        Label1.Text = "error " & e.Error.Message
    Else
        Label1.Text = "done"
    End If
End Sub
like image 42
dbasnett Avatar answered Mar 26 '23 07:03

dbasnett