【问题标题】:Marquee ProgressBar unresponsive with BackgroundWorker选取框 ProgressBar 对 BackgroundWorker 无响应
【发布时间】:2010-09-30 13:18:15
【问题描述】:

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

【问题讨论】:

    标签: vb.net progress-bar backgroundworker marquee


    【解决方案1】:

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

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

    【讨论】:

    • 当我从 DoWork() 方法调用 rvReport.RefreshReport() 时,我得到一个异常:跨线程操作无效:控件 'winRSviewer' 从它创建的线程以外的线程访问开。
    • 我想这归结为当我调用ReportViewer的RefreshReport()方法时,生成报告需要很长时间,导致表单没有响应。我做了测试,和报表没有关系,其实是ReportViewer的问题。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多