Excel VSTO应用程序中的后台工作程序,模态对话框使BGW取消变慢

时间:2011-11-25 11:03:21

标签: vb.net excel vsto backgroundworker progressdialog

我正在使用后台工作程序在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

2 个答案:

答案 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