4

我正在尝试使用 取消我的 Backgroundworker WorkerClass.bw.CancelAsync()。但它根本行不通。

//编辑!我在这里发布了完整的代码。愿这会有所帮助。好的,我添加了一些 Msgboxes 以了解 Worker 是否仍然很忙,并且有线的事情是,我有一段false时间 Worker 正在做事!?!?

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
4

2 回答 2

4

我认为您的问题是您只CancellationPending在方法开始时评估一次bw_DoWork。由于没有真正的方法BackgroundWorker在它开始之前取消它,所以CancellationPending永远是错误的并且永远不会中断工作。当您调用时,BackgroundWorker 不会使用一些魔法来接管程序计数器CancelAsync

为了使其工作,您的DoWork方法的核心逻辑必须以允许频繁轮询的方式实现,CancellationPending以便代码准确知道何时退出它正在执行的操作。你需要从这里开始:

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

更像这样的东西:

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
于 2013-06-03T14:35:09.813 回答
3

这是 BackgroundWorker 的基本模型。这是你的样子吗。

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
于 2013-06-03T11:19:37.240 回答