Marquee ProgressBarがBackgroundWorkerで応答しない
-
06-07-2019 - |
質問
私のコードでは、ボタンをクリックすると進行状況バーがマーキーに設定され、BackgroundWorkerが呼び出されますが、BackgroundWorkerが呼び出されると進行状況バーがフリーズまたは非表示になります。 BackgroundWorkerを使用して、ReportViewerのRefreshReportメソッドをUIスレッドから分離します。どんな助けも大歓迎です。ありがとう!
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
解決
問題は、 RefreshReport()
メソッドで .BeginInvoke()
を呼び出すときです。 BackgroundWorker.DoWork()
メソッドはすでに別のスレッドで発生しているため、 rvReport.RefreshReport()
を呼び出すだけです。次のようになります。
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
rvReport.RefreshReport()
End Sub
これは本当に簡単です。 Monitor
を使用してレポートオブジェクトをロックし、再入力を防止することも可能です。
今、 .BeginInvoke()
を呼び出すと、レポートプロセスが開始されますが、まったくブロックされないため、 DoWork()
には何も残りません行う方法。すぐに戻ります。この時点で、BackgroundWorkerは完了したと判断するため、プログレスバーを停止する .RunWorkerCompleted()
メソッドを呼び出します。
コメントに基づいて、 rvReport
はコンポーネントまたは単純なデータアクセスクラスではなく、視覚的なコントロールです。その場合、.Netのビジュアルコントロールはスレッドセーフではないことを知っておく必要があります。そのため、完了するまでに数分以上かかるようなことは直接決してしないでください。 RefreshReport()
メソッドの .BeginInvoke()
でジャンプしていたフープには、メインUIスレッドで長時間実行される関数を呼び出す効果がありました。
この問題を解決するには、クロススレッドチェックをオフにして例外がスローされないようにするか(単純ですが推奨されません)、コントロールの使用方法を変更して、メインの作業が他の場所で行われ、コントロールが準備ができたらイベントを発生させます。コントロールをその程度まで変更できない場合、それはコントロールの設計上の欠陥です。
他のヒント
問題は、バックグラウンドtheadにプロセッサがある間、進行状況バーに再描画する機会が与えられていないことです。そのため、処理中にメインの待機スレッドからSystem.Windows.Forms.Application.DoEvents()を呼び出す必要があります。これによりコントロールが取得され、進行状況バーが再描画されます。
したがって、BackgroundWorker1.RunWorkerAsyncを呼び出した後、イベントが発生するまでDoEventsを呼び出すループを追加し、RunWorkerCompletedでイベントを発生させて、呼び出し元のコードを終了できます。これによりメインコードの実行を継続できないため、コールをバックグラウンドコールまたは別のスレッドに入れることができます。