4

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

2 回答 2

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

真的就这么简单,可能还可以使用 aMonitor来锁定您的报表对象并防止重新输入。

现在,当您调用.BeginInvoke()报告过程时,它会启动,但它根本不会阻塞,因此该DoWork()方法没有什么可做的。它只是立即返回。此时 BackgroundWorker 认为它已经完成,因此调用该.RunWorkerCompleted()方法,这会停止您的进度条。


基于注释,rvReport是一个可视化控件而不是一个组件或简单的数据访问类。在这种情况下,您应该知道 .Net 中的可视控件不是线程安全的,因此永远不应该直接执行任何需要花费几分钟才能完成的操作。.BeginInvoke()您在该方法中跳过的循环具有在主 UI 线程RefreshReport()中调用您长时间运行的函数的效果。

要解决此问题,您需要关闭跨线程检查以便不抛出异常(简单,但不推荐)或更改您使用控件的方式,以便主要工作发生在其他地方并且控件只是在以下情况下引发事件东西准备好了。如果您无法将控件修改到该程度,则这是控件中的设计缺陷。

于 2009-01-09T19:37:30.210 回答
-1

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

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

于 2009-01-09T19:09:22.093 回答