Backgroundworker的CancelAsync()方法无法工作

4
我正在尝试使用 WorkerClass.bw.CancelAsync() 取消我的 Backgroundworker。但它根本不起作用。 // 编辑! 我在这里发布了完整的代码。也许这会有所帮助。 好吧,我添加了一些消息框来知道工作程序是否仍在忙碌,而奇怪的是,当工作者正在执行任务时,我获得了一个 false!?!?
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

1
你设置了 WorkerClass.bw.WorkerSupportsCancellation = True 吗?否则它将不会取消任何东西。 - Nico Schertler
我已经完成了,请您再过目一遍 =)。 - Ponch0
已经添加了这部分。取消检查不是问题。它运行良好。我的问题是,工作人员告诉我它没有忙? - Ponch0
你能在按钮点击处理程序中加入一个 CancelAsync 并确认它是否被调用了吗? - mclark1129
天啊,我真是个白痴......就这样了。无法想象我有多蠢。有时候最简单的事情也会成为错误 :) 谢谢 Mike! - Ponch0
显示剩余2条评论
3个回答

4
我认为你的问题在于你只在 bw_DoWork 方法开始时评估了 CancellationPending 一次。由于没有真正的方法在启动 BackgroundWorker 之前取消它, CancellationPending 将始终为false,并且永远不会中断工作。当您调用 CancelAsync 时,BackgroundWorker并不使用某些魔法来接管程序计数器。
为使此方法起作用,您的 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

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

不完全相同,但大部分应该与我的代码一致。所有功能都正常,除了CancelAsync() - Ponch0
好的,我尝试使用你的代码编辑我的代码,但是worker.IsBusy总是返回布尔值false。不知道为什么,因为工作线程正在运行? - Ponch0
在调用RunWorkerAsync之后,后台工作线程实际开始并更新属性为“True”之前可能会有延迟。生成新线程并开始执行代码需要时间。您下一行检查“IsBusy”(再次,仅一次)可能发生在任何完成之前。如果您放入一些任意的延迟(比如3000毫秒),那么它可能会起作用。 - mclark1129
好的,你是对的。但这仍然没有解决我的问题。我仍然无法取消工作人员。即使使用简单的 For Next Statement 也不行。 - Ponch0

0
创建: 1个名为"Form1"的表单,
包含 1个名为"Button1"的按钮, 1个名为"ProgressBar1"的进度条。
然后粘贴以下代码:
Imports System.ComponentModel

Public Class Form1

' Create a BackgroundWorker instance
Private WithEvents backgroundWorker1 As New System.ComponentModel.BackgroundWorker()


Public Sub New()
    InitializeComponent()

    ' Configure the BackgroundWorker
    backgroundWorker1.WorkerReportsProgress = True
    backgroundWorker1.WorkerSupportsCancellation = True
End Sub


Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' Set the ProgressBar properties
    progressBar1.Minimum = 0
    progressBar1.Maximum = 100
    progressBar1.Value = 0
End Sub


' Event handler for the Start button click
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Cancel the BackgroundWorker if it's running
    If backgroundWorker1.IsBusy Then
        backgroundWorker1.CancelAsync()
    Else
        backgroundWorker1.RunWorkerAsync()
        Button1.Text = "Cancel"
    End If
End Sub


' Event handler for the BackgroundWorker's DoWork event
Private Sub backgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles backgroundWorker1.DoWork
    For i As Integer = 0 To 100
        ' Check if cancellation is requested
        If backgroundWorker1.CancellationPending Then
            e.Cancel = True
            Exit For
        End If

        ' Simulate work by sleeping for a short duration
        System.Threading.Thread.Sleep(10)

        ' Report progress to the UI thread
        backgroundWorker1.ReportProgress(i)
    Next
End Sub


' Event handler for the BackgroundWorker's ProgressChanged event
Private Sub backgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles backgroundWorker1.ProgressChanged
    ' Update the ProgressBar value based on the reported progress
    progressBar1.Value = e.ProgressPercentage
End Sub


' Event handler for the BackgroundWorker's RunWorkerCompleted event
Private Sub backgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles backgroundWorker1.RunWorkerCompleted
    ' Perform any cleanup or post-processing after the backgroundWorker has either finished, or aborted

    If ProgressBar1.Value = 100 Then
        MessageBox.Show("Progress completed!")
        Button1.Text = "Start"
        'ProgressBar1.Value = 0 ' uncomment this is you want it to reset after a completion as well
    Else
        MessageBox.Show("Operation Aborted!")
        ProgressBar1.Value = 0
        Button1.Text = "Start"
    End If
End Sub


End Class

单个按钮在backgroundWorker忙碌与否的情况下,可以在“开始”和“取消”之间切换。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接