我遇到了一個問題,我可以用Application.DoEvents修復,但不想離開它,因爲它可能會引入各種討厭的問題。想要調用相同的BackgroundWorker多次沒有使用Application.DoEvents
背景: 我們的應用程序主要是一個桌面應用程序,它可以對Web服務進行多次調用。我們控制着一切,但整體系統設計的變化不會被認真考慮。其中一個調用Calculate經常使用,偶爾可能需要幾分鐘時間來處理所有數據以返回有效結果。
此前對Calculate的調用是同步完成的,因此會阻止用戶界面讓用戶懷疑應用程序是否已凍結等。我已成功將所有長等待調用移動到BackgroundWorker,然後創建簡單的等待屏幕可以循環顯示「正在計算...」動畫消息。
現在問題出現時,我們的UI代碼嘗試在第一次完成之前再次調用計算例程。我會得到一個「此BackgroundWorker目前正忙,無法運行多個實例...」消息。我認爲應該由resetEvent.WaitOne()調用來控制。它沒有,所以我想可能是另一個控制整個例程訪問的事件會有所幫助,所以我添加了calcDoneEvent。這仍然沒有解決問題,但會導致它在第二次調用Calculate的calcDoneEvent.WaitOne()調用時無限期地阻塞。然後在奇想中,我將Application.DoEvents添加到Calculate和viola的底部,解決了問題。
我不想在那裏留下那個.DoEvents,因爲我讀過它會導致以後很難追查的問題。有沒有更好的方法來處理這種情況?
在此先感謝..
Private WithEvents CalculateBGW As New System.ComponentModel.BackgroundWorker
Dim resetEvent As New Threading.AutoResetEvent(False)
Dim calcDoneEvent As New Threading.AutoResetEvent(True)
Public Sub Calculate()
calcDoneEvent.WaitOne() ' will wait if there is already a calculate running.'
calcDoneEvent.Reset()
' setup variables for the background worker'
CalculateBGW.RunWorkerAsync() ' Start the call to calculate'
Dim nMsgState As Integer = 0
' will block until the backgorundWorker is done'
Do While Not resetEvent.WaitOne(200) ' sleep for 200 miliseconds, then update the status window'
Select Case nMsgState
Case 1
PleaseWait(True, vbNull, "Calculating. ")
Case 2
PleaseWait(True, vbNull, "Calculating.. ")
Case 3
PleaseWait(True, vbNull, "Calculating... ")
Case 4
PleaseWait(True, vbNull, "Calculating....")
Case Else
PleaseWait(True, vbNull, "Calculating ")
End Select
nMsgState = (nMsgState + 1) Mod 5
Loop
PleaseWait(False, vbNull) 'make sure the wait screen goes away'
calcDoneEvent.Set() ' allow another calculate to proceed'
Application.DoEvents() ' I hate using this here'
End Sub
Private Sub CalculateBGW_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CalculateBGW.DoWork
Try
'make WS Call, do data processing on it, can take a long time..'
'No Catch inside the DoWork for BGW, or exception handling wont work right...'
'Catch'
Finally
resetEvent.Set() 'unblock the main thread'
End Try
End Sub
Private Sub CalculateBGW_RunWorkerCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles CalculateBGW.RunWorkerCompleted
'If an error occurs we must check e.Error prior to touching e.Result, or the BGW'
'will possibly "eat" the exception for breakfast (I hear theyre tasty w/ jam)'
If Not (e.Error Is Nothing) Then
'If a Web Exception timeout, retry the call'
If TypeOf e.Error Is System.Net.WebException And _
e.Error.Message = "The operation has timed out" And _
intRetryCount < intRetryMax Then
' Code for checking retry times, increasing timeout, then possibly recalling the BGW'
resetEvent.Reset()
CalculateBGW.RunWorkerAsync() 'restart the call to the WS'
Else
Throw e.Error ' after intRetryMax times, go ahead and throw the error up higher'
End If
Else
Try
'normal completion stuff'
Catch ex As Exception
Throw
End Try
End If
End Sub
我認爲你只是可能會在那裏。如果在這臺古老的計算機上重新打開IDE,並不需要很長時間,我現在就可以嘗試,但它會一直等到第一天。 – 2010-03-04 23:48:03