在我的代码中,当单击一个按钮时,进度条设置为选取框,然后调用我的BackgroundWorker,但是当调用BackgroundWorker时,进度条会冻结或消失。我使用BackgroundWorker从UI线程中分离ReportViewer的RefreshReport方法。任何帮助表示赞赏。谢谢!
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
答案 0 :(得分:3)
问题是当您在.BeginInvoke()
方法中拨打RefreshReport()
时。 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中的可视控件不是线程安全的,因此永远不会直接执行任何需要花费一些时间才能完成的操作。您在.BeginInvoke()
方法中使用RefreshReport()
跳过的箍具有在主UI线程中调用长时间运行函数的效果。
要解决此问题,您需要关闭跨线程检查以便不抛出异常(简单但不推荐)或更改您使用控件的方式,以便主要工作在其他地方发生并且控件只是事情准备就绪时提出事件。如果你无法将控件修改到那个程度,那么它就是控件中的设计缺陷。
答案 1 :(得分:-1)
问题在于,当后台有处理器时,进度条没有机会重新绘制。因此,您需要在处理时从主等待线程调用System.Windows.Forms.Application.DoEvents()。这将获得控制并导致进度条重新绘制。
因此,在BackgroundWorker1.RunWorkerAsync调用之后,您可以添加一个循环来调用DoEvents,直到引发事件,然后在RunWorkerCompleted中引发事件以使调用代码退出。由于这不允许主代码继续运行,您可以将调用放入后台调用或其他线程中。