该应用程序的功能远不止这些,但我已通过以下示例缩小了问题范围。
当bgwDone.WaitOne()被注释掉时,进度条工作正常,取消按钮有效,但在后台进程完成之前继续执行。
当应用bgwDone.WaitOne()时,ProgressForm可见但未启用,因此无法取消处理并且不会刷新进度条,而且最令人困惑的部分是Msgbox(&#34; 1&#34;)< em>不执行。我只在后台工作程序完成后才看到Msgbox(&#34; 2&#34;)。我完全感到困惑。
Imports System.ComponentModel
Public Class Form1
Private WithEvents bgw As BackgroundWorker
Private Event bgwCancelled()
Private bgwDone As New System.Threading.AutoResetEvent(False)
'Allows ProgressForm to cancel execution
Public Sub bgwCancelAsync()
RaiseEvent bgwCancelled()
End Sub
Private Sub bgw_Cancelled_by_ProgressForm() Handles Me.bgwCancelled
bgw.CancelAsync()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Cursor = Cursors.WaitCursor
bgw = New BackgroundWorker
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
If bgw.IsBusy = False Then
ProgressForm.Show()
bgw.RunWorkerAsync(10)
End If
'********THIS LINE: bgwDone.WaitOne() MAKES A BIG DIFFERENCE*******
bgwDone.WaitOne()
MsgBox("1")
MsgBox("2")
Cursor = Cursors.Default
End Sub
'BackgroundWorker.RunWorkerAsync raises the DoWork event
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
Dim numToDo As Integer = CInt(e.Argument)
For n As Integer = 1 To numToDo
If bgw.CancellationPending Then
Exit For
End If
System.Threading.Thread.Sleep(200)
bgw.ReportProgress(n * 10)
Next
bgwDone.Set()
End Sub
'ReportProgress raises the ProgressChanged event
Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
ProgressForm.UpdateProgress(e.ProgressPercentage)
End Sub
Private Sub bgw_RunWorkerCompleted(sender As Object,
e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
ProgressForm.Close()
End Sub
我的表格与ProgressBar:
Public Class ProgressForm
Private Sub ButtonCancel_Click(sender As Object, e As EventArgs) Handles ButtonCancel.Click
Form1.bgwCancelAsync()
End Sub
Public Sub UpdateProgress(pct As Integer)
ProgressBar1.Value = pct
ProgressBar1.Refresh()
End Sub
End Class
答案 0 :(得分:1)
我不确定你想要完成什么。但是,您的某些代码似乎试图破坏BackGroundWorker
的目的:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Cursor = Cursors.WaitCursor
bgw = New BackgroundWorker
...
If bgw.IsBusy = False Then
ProgressForm.Show()
bgw.RunWorkerAsync(10)
End If
bgwDone.WaitOne()
MsgBox("1")
MsgBox("2")
Cursor = Cursors.Default
End Sub
BackgroundWorker
的目的是在另一个线程上执行一些长时间运行的任务,并使UI保持响应。我不确定只有&#34; 需要几秒钟的任务&#34;有资格作为一个长期运行的任务。
WaitCursor
?离开UI resposive的目的是允许用户在此期间做其他事情。 bgw.IsBusy
的测试永远不会是真的 - 你刚刚创建了3行。再次单击该按钮,您将创建另一个BGW。BGW
完成后继续下一行。这不是它的工作原理。
Me.UseWaitCursor
)直到填充内容。这并不排除ProgressBar
。 StatusBar
可以包含ProgressBar
,并且更加微妙(也许是合适的,因为 是一个状态元素)。 因此,修改并使用进度记者的表单实例:
Private WithEvents bgw As BackgroundWorker
Private frmProg As ProgressForm
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
bgw = New BackgroundWorker
End Sub
Private Sub btnLoadAll_Click(sender As Object, e As EventArgs) Handles btnLoadAll.Click
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
If bgw.IsBusy = False Then
' create ProgressForm instance if needed
If frmProg Is Nothing Then frmProg = New ProgressForm
frmProg.Show()
bgw.RunWorkerAsync(78)
End If
btnLoadAll.Enabled = False
End Sub
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
' multiple workers can use the same event
Dim thisWorker = DirectCast(sender, BackgroundWorker)
Dim count = Convert.ToInt32(e.Argument)
For n As Integer = 1 To count
If thisWorker.CancellationPending Then
Exit For
End If
' Fake work:
System.Threading.Thread.Sleep(50)
' dont assume the size of the job if
' there are multiple BGW or tasks
thisWorker.ReportProgress(Convert.ToInt32((n / count) * 100))
Next
End Sub
Private Sub bgw_ProgressChanged(sender As Object,
e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
frmProg.UpdateProgress(e.ProgressPercentage)
End Sub
Private Sub bgw_RunWorkerCompleted(sender As Object,
e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'... ToDo
ElseIf e.Cancelled Then
'... ToDo
Else
frmProg.Close()
' avoid 'cannot access disposed object':
frmProg = Nothing
Me.btnNextStep.Enabled = True
btnLoadAll.Enabled = True
End If
End Sub
而不是启用&#34; Next&#34;按钮,应用程序可以自动进行。这取决于应用程序。