You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CrystalReportViewer.RefreshReport在BackgroundWorker中运行时挂起问题

问题根因

你遇到的死锁问题核心是所有Windows窗体控件、UI元素的操作必须在UI线程执行,而你把ShowReport()方法、frmReportPreview窗体创建、CrystalReportViewer控件操作的逻辑都放在了BackgroundWorker的DoWork回调中,该回调运行在独立工作线程,跨线程操作UI会导致线程阻塞、消息循环卡死,最终触发ContextSwitchDeadlock异常。


解决方案

调整逻辑边界:DoWork中仅执行报表模板加载、数据源绑定、数据计算等纯非UI操作,所有窗体创建、控件赋值逻辑全部移到RunWorkerCompleted回调中执行,该回调默认运行在UI线程,不会出现跨线程问题。

调整后dlgReportLoading代码

Imports System.Windows.Forms

Public Class dlgReportLoading
    Private DisplayReport As Common.CRReport
    Private WithEvents LoadReportWorker As System.ComponentModel.BackgroundWorker
    ' 存储后台生成好的报表文档对象
    Private _generatedReport As CrystalDecisions.CrystalReports.Engine.ReportDocument
    ' 存储当前操作类型
    Private _operationType As Common.CRReport.GenerateReportOption

    Public Sub New(ByRef Report As Common.CRReport)
        InitializeComponent()
        DisplayReport = Report
        _operationType = Report.ReportOption
    End Sub

    Private Sub dlgReportLoading_Load(sender As Object, e As EventArgs) Handles Me.Load
        Me.Cursor = Cursors.WaitCursor
        Me.TopMost = True
        Me.TopMost = False

        LoadReportWorker = New System.ComponentModel.BackgroundWorker
        LoadReportWorker.RunWorkerAsync()
    End Sub

    Private Sub dlgReportLoading_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
        Me.Cursor = Cursors.Default
    End Sub

    Private Sub LoadReport_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles LoadReportWorker.DoWork
        If _operationType = Common.CRReport.GenerateReportOption.None Then Exit Sub

        ' 后台仅执行报表数据准备、模板加载等非UI操作
        DisplayReport.PrepareReport()
        Select Case _operationType
            Case Common.CRReport.GenerateReportOption.DisplayOnScreen
                ' 只返回准备好的报表对象,不操作UI
                _generatedReport = DisplayReport.GetPreparedReportDocument()
            Case Common.CRReport.GenerateReportOption.SendToPrinter
                DisplayReport.PrintReport()
            Case Common.CRReport.GenerateReportOption.ExportToFile
                DisplayReport.ExportReport()
        End Select
        DisplayReport.ReportOption = Common.CRReport.GenerateReportOption.None
    End Sub

    Private Sub LoadReport_Complete(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles LoadReportWorker.RunWorkerCompleted
        ' UI操作全部放在UI线程的回调中执行
        If _operationType = Common.CRReport.GenerateReportOption.DisplayOnScreen AndAlso _generatedReport IsNot Nothing Then
            Dim ReportViewer As New frmReportPreview(_generatedReport)
            With ReportViewer
                .WindowState = FormWindowState.Maximized
                .Show()
            End With
        End If
        ' 关闭加载屏
        Me.DialogResult = DialogResult.OK
        Me.Close()
    End Sub
End Class

补充CRReport类方法

在Common.CRReport类中新增方法,返回已经准备好的报表文档对象:

Protected Friend Function GetPreparedReportDocument() As CrystalDecisions.CrystalReports.Engine.ReportDocument
    ' 返回你PrepareReport方法中生成的ReportDocument实例即可
    Return Me.CrystalReport
End Function

调整后frmReportPreview代码

移除原来的跨线程操作风险,直接接收准备好的报表对象,删掉Shown事件中的多余刷新逻辑:

Imports System.ComponentModel

Public Class frmReportPreview
    Private ReportToDisplay As CrystalDecisions.CrystalReports.Engine.ReportDocument

    Public Sub New(ByVal report As CrystalDecisions.CrystalReports.Engine.ReportDocument)
        InitializeComponent()
        ReportToDisplay = report
        Me.rptViewer.ReportSource = ReportToDisplay
        Me.rptViewer.Zoom(1)
    End Sub

    Private Sub frmReportPreview_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        ReportToDisplay.Dispose()
        Me.rptViewer.ReportSource = Nothing
    End Sub
End Class

其他说明

如果后续想用Async/Await方案,逻辑和上述调整完全一致:Await块中仅执行非UI的报表准备逻辑,后续UI操作都放在Await之后执行即可,代码会更简洁。

内容的提问来源于stack exchange,提问作者G_Hosa_Phat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 17:45:08