Marquee ProgressBar 对 BackgroundWorker 无响应
在我的代码中,当单击按钮时,进度条设置为选取框,然后调用我的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
In my code, when a button is clicked the progress bar is set to marquee and then my BackgroundWorker is called but when the BackgroundWorker is called the progress bar freezes or disappears. I use the BackgroundWorker to seperate the RefreshReport method of the ReportViewer from the UI thread. Any help is appreciated. Thanks!
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题是当您在
RefreshReport()
方法中调用.BeginInvoke()
时。BackgroundWorker.DoWork()
方法已在不同的线程中引发,因此您只需调用rvReport.RefreshReport()
即可。 它应该看起来像这样:确实就是这么简单,可以添加使用
Monitor
来锁定报表对象并防止重新进入。现在,当您调用
.BeginInvoke()
时,报告进程就会启动,但它根本不会阻塞,因此DoWork()
方法无需执行任何操作。 它立即返回。 此时,BackgroundWorker 认为已完成,因此调用.RunWorkerCompleted()
方法,该方法会停止进度条。根据评论,
rvReport
是一个可视化控件,而不是一个组件或简单的数据访问类。 在这种情况下,您应该知道 .Net 中的可视控件不是线程安全的,因此永远不要直接执行任何需要花费几分钟才能完成的操作。 您在RefreshReport()
方法中使用.BeginInvoke()
进行的操作具有在主 UI 线程中调用长时间运行的函数的效果嗯>。要解决此问题,您需要关闭跨线程检查,以便不引发异常(简单,但不推荐),或者更改使用控件的方式,以便主要工作发生在其他地方,并且控件仅在以下情况下引发事件:事情已经准备好了。 如果您无法将控件修改到那种程度,则说明控件存在设计缺陷。
The problem is when you call
.BeginInvoke()
in yourRefreshReport()
method. TheBackgroundWorker.DoWork()
method is already raised in a different thread, so you can just callrvReport.RefreshReport()
. It should look like this:It really is that simple, with the possible addition of using a
Monitor
to lock your report object and prevent re-entry.Right now, when you call
.BeginInvoke()
the report process kicks off, but it doesn't block at all so there's nothing left for theDoWork()
method to do. It just returns right away. At this point the BackgroundWorker thinks it's done, so calls the.RunWorkerCompleted()
method, which stops your progress bar.Based on the comment,
rvReport
is a visual control rather than a component or simple data access class. In that case, you should know that visual controls in .Net are not thread safe, and therefore should never directly do anything directly that takes more than a few moments to complete. The hoops you were jumping through with.BeginInvoke()
in theRefreshReport()
method had the effect of calling your long running function in the main UI thread.To solve this problem, you need to either turn off cross thread checking so that the exception is not thrown (simple, but not recommended) or change how you use the control, so that the main work happens elsewhere and the control just raises events when things are ready. If you can't modify the control to that extent, it's a design flaw in the control.
问题在于,当背景标题有处理器时,进度条没有机会重新绘制。 因此,您需要在处理时从主等待线程调用 System.Windows.Forms.Application.DoEvents()。 这将获得控制并导致进度条重新绘制。
因此,在BackgroundWorker1.RunWorkerAsync 调用之后,您可以添加一个循环来调用DoEvents,直到引发事件,然后在RunWorkerCompleted 中引发事件以使调用代码退出。 由于这不允许主代码继续运行,您可以将调用放在后台调用或另一个线程中。
The problem is that the progress bar is not being given a chance to repaint while the background thead has the processor. So you need to call System.Windows.Forms.Application.DoEvents() from the main waiting thread while you are processing. This will get control and cause the progress bar to repaint.
So after the BackgroundWorker1.RunWorkerAsync call you can add a loop to call DoEvents until an event is raised and then raise the event in RunWorkerCompleted to let the calling code exit. Since this doesnt allow the main code to continue running you could put the call in the Background call or another thread.