Marquee ProgressBar ne répond pas avec BackgroundWorker
-
06-07-2019 - |
Question
Dans mon code, lorsqu'un clic est effectué sur un bouton, la barre de progression est définie sur sélection et mon BackgroundWorker est appelé, mais lorsque BackgroundWorker est appelé, la barre de progression se fige ou disparaît. J'utilise BackgroundWorker pour séparer la méthode RefreshReport de ReportViewer à partir du thread d'interface utilisateur. Toute aide est appréciée. Merci!
Private Sub btnOtherReport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOtherReport.Click
rvReport.ProcessingMode = ProcessingMode.Remote
rvReport.ShowParameterPrompts = False
rvReport.ServerReport.ReportServerUrl = New Uri("REPORT_SERVER_URL")
rvReport.ServerReport.ReportPath = "REPORT_PATH"
rvReport.BackColor = Color.White
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
RefreshReport()
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
pbReports.Style = ProgressBarStyle.Blocks
pbReports.Value = 100
End Sub
Public Sub RefreshReport()
rvReport.BeginInvoke(New MethodInvoker(AddressOf rvReport.RefreshReport))
End Sub
La solution
Le problème survient lorsque vous appelez .BeginInvoke ()
dans votre méthode RefreshReport ()
. La méthode BackgroundWorker.DoWork ()
est déjà générée dans un autre thread, vous pouvez donc simplement appeler rvReport.RefreshReport ()
. Cela devrait ressembler à ceci:
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
rvReport.RefreshReport()
End Sub
C’est aussi simple que cela, avec l’ajout possible d’un Moniteur
pour verrouiller l’objet de rapport et éviter toute nouvelle saisie.
À l'heure actuelle, lorsque vous appelez .BeginInvoke ()
, le processus de rapport démarre, mais il ne bloque pas du tout, il ne reste donc plus rien pour le DoWork ()
. méthode à faire. Ça revient tout de suite. À ce stade, BackgroundWorker pense que c'est fait et appelle donc la méthode .RunWorkerCompleted ()
, qui arrête la barre de progression.
D'après le commentaire, rvReport
est un contrôle visuel plutôt qu'un composant ou une simple classe d'accès aux données. Dans ce cas, vous devez savoir que les contrôles visuels dans .Net ne sont pas thread-safe et que, par conséquent, jamais ne doit directement rien faire qui prenne plus que quelques instants. Les cerceaux que vous parcouriez avec .BeginInvoke ()
dans la méthode RefreshReport ()
ont eu pour effet d'appeler votre longue fonction dans le thread d'interface utilisateur principal .
Pour résoudre ce problème, vous devez désactiver la vérification des fils croisés de manière à ce que l'exception ne soit pas levée (simple, mais non recommandée), ou modifier la manière dont vous utilisez le contrôle, afin que le travail principal soit effectué ailleurs et que le contrôle juste soulève des événements lorsque les choses sont prêtes. Si vous ne pouvez pas modifier le contrôle dans cette mesure, il s'agit d'un défaut de conception du contrôle.
Autres conseils
Le problème est que la barre de progression n’a pas la chance de se repeindre tant que l’arrière-plan a le processeur. Vous devez donc appeler System.Windows.Forms.Application.DoEvents () à partir du thread en attente principal pendant le traitement. Cela permettra d’obtenir le contrôle et de repeindre la barre de progression.
Ainsi, après l'appel de BackgroundWorker1.RunWorkerAsync, vous pouvez ajouter une boucle pour appeler DoEvents jusqu'à ce qu'un événement soit déclenché, puis déclencher l'événement dans RunWorkerCompleted pour laisser le code d'appel quitter. Comme cela ne permet pas au code principal de continuer à s'exécuter, vous pouvez placer l'appel dans l'appel en arrière-plan ou dans un autre thread.