在我的代码中,当单击一个按钮时,进度条设置为选取框,然后调用我的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
有帮助吗?

解决方案

问题是当您在 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线程中调用长时间运行的函数的效果

要解决此问题,您需要关闭跨线程检查以便不抛出异常(简单但不推荐)或更改您使用控件的方式,以便主要工作在其他地方发生并且控件只是事情准备就绪时提出事件。如果你无法将控件修改到那个程度,那么它就是控件中的设计缺陷。

其他提示

问题在于,当后台有处理器时,进度条没有机会重新绘制。因此,您需要在处理时从主等待线程调用System.Windows.Forms.Application.DoEvents()。这将获得控制并导致进度条重新绘制。

因此,在BackgroundWorker1.RunWorkerAsync调用之后,您可以添加一个循环来调用DoEvents,直到引发事件,然后在RunWorkerCompleted中引发事件以使调用代码退出。由于这不允许主代码继续运行,您可以将调用放入后台调用或其他线程中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top