Je rencontre un problème que j'ai pu résoudre avec Application.DoEvents, mais je ne veux pas le laisser car il pourrait introduire toutes sortes de problèmes désagréables.Vous voulez appeler même BackgroundWorker plusieurs fois sans utiliser Application.DoEvents
Contexte: Notre application est principalement une application de bureau qui effectue de nombreux appels à un service Web. Nous contrôlons tout mais les modifications apportées à la conception globale du système ne seront pas sérieusement prises en compte. L'un de ces appels, Calculer, est très souvent utilisé, et il peut parfois prendre quelques minutes pour traiter toutes les données afin de renvoyer des résultats valides. Auparavant, cet appel à Calculate était effectué de manière synchrone et bloquait ainsi l'interface utilisateur, laissant l'utilisateur se demander si l'application était gelée ou non, etc. J'ai réussi à transférer tous les longs appels à BackgroundWorker, puis j'ai effectué un écran d'attente simple qui ferait défiler un message animé "Calculer ...".
Maintenant, le problème se pose lorsque notre code d'interface utilisateur tente d'appeler à nouveau le sous-programme de calcul avant la fin du premier. Je recevrais un message "This BackgroundWorker est actuellement occupé et ne peut pas exécuter plusieurs instances ...". Ce que je pensais devrait être contrôlé par les appels resetEvent.WaitOne(). Ce n'était pas le cas, je pensais que peut-être un autre événement contrôlant l'accès à la routine entière aiderait, donc j'ai ajouté le calcDoneEvent. Cela ne résolvait toujours pas le problème, mais le bloquait indéfiniment lors du 2ème appel de l'appel calcDoneEvent.WaitOne() de Calculate. Ensuite, sur un coup de tête, j'ai ajouté le Application.DoEvents au fond de Calculer et alto, problème résolu.
Je ne veux pas laisser cela. Eviter là parce que je l'ai lu peut causer des problèmes qui plus tard sont très difficiles à traquer. Y a-t-il une meilleure façon de gérer cette situation?
Merci à l'avance ..
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
Je pense que vous pourriez être sur quelque chose là-bas. Si cela ne prenait pas tellement de temps pour rouvrir l'IDE sur cet ancien ordinateur, je l'essayerais maintenant, mais au lieu de cela, il attendra jusqu'au matin. –