我正在使用后台工作程序在Excel VSTO应用程序中抛出一个带状态栏和取消按钮的进度对话框,以逃避长时间运行的计算。除了一个问题,它的工作非常好。我想使用模态对话框,以便对话框后面的UI被锁定,而不是无模式对话框。如果我使用.ShowDialog()而不是.Show(),一切都很棒,直到您点击表单上的取消按钮。跟随调试器中的事情,取消发生,它只需要在30秒的范围内。如果我在表单上使用.Show(),那么取消会立即发生。
我确信我忽略了一些相当简单的事情...任何帮助都会非常感激......
Private WithEvents BGW As BackgroundWorker
Private PD As ProgressDialog
Public Sub BGW_DoCalculation(Mode As RunMode)
'Set the Synchronization Context
System.Threading.SynchronizationContext.SetSynchronizationContext(New WindowsFormsSynchronizationContext())
'Setup the Background Worker
BGW = New BackgroundWorker
BGW.WorkerReportsProgress = True
BGW.WorkerSupportsCancellation = True
'Starts the Background Process
If BGW.IsBusy = False Then
BGW.RunWorkerAsync(Mode)
Else
Exit Sub
End If
'Start the Process Dialog Box
PD = New ProgressDialog
'Add a handler to cancel background worker
AddHandler PD.Cancel_Button.Click, AddressOf CancelBackGroundWorker
PD.ShowDialog()
End Sub
Private Sub CancelBackGroundWorker(sender As Object, e As System.EventArgs)
BGW.CancelAsync()
End Sub
Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
If BGW.CancellationPending = False Then
Dim Mode As RunMode = CType(e.Argument, RunMode)
LongRunningCalc(Mode)
Else
e.Cancel = True
Return
End If
End Sub
Private Sub BGW_WorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
PD.Dispose()
BGW.Dispose()
End Sub
Private Sub BGW_WorkerProgress(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
PD.ProgressBar1.Maximum = 100
If Not BGW.CancellationPending Then
PD.ProgressBar1.Value = e.ProgressPercentage
PD.PercentCompleteLabel.Text = e.ProgressPercentage & "%"
'Update the message Label
PD.MessageLabel.Text = e.UserState.ToString
End If
End Sub
'This is shortened for the posting...
Public Sub LongRunningCalc(ByVal Mode As RunMode)
'Do long running calc - obviously this isn't the calc ;)
For i = 0 to 1000000000000000
i+1
End For
If BGW.CancellationPending = True Then
'Report Progress
BGW.ReportProgress(CInt(((Scen) / TotalScen) * 100), "Canceling Calculation, Please Wait")
'Output the scenarios that have been calculated...
Call Globals.ThisWorkbook.OutScen(Scen, Count)
Return
End If
End Sub
答案 0 :(得分:0)
非常确定添加对Application.DoEvents的常规调用会对您有所帮助(我的代码中没有看到任何内容)。取消单击将添加到Windows消息队列中。调用Application.DoEvents显式强制应用程序处理未完成的队列消息。
另请参阅:Application.DoEvents
答案 1 :(得分:0)
经过几个小时的阅读后我终于回到了下面的帖子并实现了一个AutoResetEvent
这个答案对我有用,并且避免任何Application.DoEvent废话!
How to wait for a BackgroundWorker to cancel?
Private _resetEvent As New AutoResetEvent(False)
Private Sub CancelBackGroundWorker(ByVal sender As Object, ByVal e As System.EventArgs)
BGW.CancelAsync()
_resetEvent.WaitOne()
End Sub
'This is shortened for the posting...
Public Sub LongRunningCalc(ByVal Mode As RunMode)
'Do long running calc - obviously this isn't the calc ;)
For i = 0 to 1000000000000000
i+1
End For
If BGW.CancellationPending = True Then
'Report Progress
BGW.ReportProgress(CInt(((Scen) / TotalScen) * 100), "Canceling Calculation, Please Wait")
'Output the scenarios that have been calculated...
Call Globals.ThisWorkbook.OutScen(Scen, Count)
_resetEvent.Set()
Return
End If
_resetEvent.Set()
End Sub