如何使用 BackGroundWorker 刷新 DataGridView

Posted

技术标签:

【中文标题】如何使用 BackGroundWorker 刷新 DataGridView【英文标题】:How to refresh DataGridView with BackGroundWorker 【发布时间】:2020-09-23 14:07:47 【问题描述】:

我正在尝试创建一个接收文件路径列表并按顺序打印所有这些文件的应用程序。打印文件时,您可以取消打印或在列表中移动文件。一切正常,但我不知道如何在每次更新后刷新 DataGridView。那么请有人可以帮助我吗? 这是我的代码,我尝试使用 BackgroundWorker_ProgressChanged 来更新 datagridview 但我知道这不是最好的做法。

Private Sub btnCancelPrint_Click(sender As Object, e As EventArgs) Handles btnCancelPrint.Click
    Dim msg = "Annullare la stampa di tutti i documenti?"
    Dim title = "Annulla Stampa"
    Dim style = MsgBoxStyle.YesNo Or MsgBoxStyle.DefaultButton2 Or
                MsgBoxStyle.Critical
    Dim response = MsgBox(msg, style, title)
    If response = MsgBoxResult.Yes Then
        If BackgroundWorkerPrint.IsBusy Then
            If BackgroundWorkerPrint.WorkerSupportsCancellation Then
                btnPrint.Enabled = True
                btnCancelPrint.Enabled = False
                BackgroundWorkerPrint.CancelAsync()
            End If
        End If
    End If

End Sub
Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click
    Try
        If BackgroundWorkerPrint.IsBusy <> True Then
            btnPrint.Enabled = False
            BackgroundWorkerPrint.RunWorkerAsync()
        End If
    Catch ex As Exception
    End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorkerPrint.DoWork
    printFont = New Font("Arial", 10)
    Dim pd As New PrintDocument()
    Dim pDialog As New PrintDialog()
    Dim ps As New PrinterSettings()
    Dim psize As New PaperSize()
    pd.DefaultPageSettings.Landscape = False
    pDialog.Document = pd
    pDialog.Document.DefaultPageSettings.PaperSize = psize
    AddHandler pd.PrintPage, AddressOf PrintDoc_PrintPage
    Dim result As New DialogResult
    result = pDialog.ShowDialog()
    BackgroundWorkerPrint.ReportProgress(0)
    BackgroundWorkerPrint.ReportProgress(4)
    For Each fattura As Fattura In DataGridFatture.DataSource
        Thread.Sleep(10000)
        If BackgroundWorkerPrint.CancellationPending Then
            BackgroundWorkerPrint.ReportProgress(2)
            e.Cancel = True
            Exit For
        End If
        If (fattura.Stato <> Fattura.Semaforo.STAMPATO) Then
            pathDoc = fattura.Path
            BackgroundWorkerPrint.ReportProgress(3)
            Try
                streamToPrint = New StreamReader(fattura.Path)
                Try
                    If (result = DialogResult.OK) Then
                        pd.Print()
                        BackgroundWorkerPrint.ReportProgress(1)
                    End If
                Finally
                    streamToPrint.Close()
                End Try
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End If
    Next
    BackgroundWorkerPrint.ReportProgress(5)
End Sub
Private Sub BackgroundWorkerPrint_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorkerPrint.ProgressChanged
    Select Case e.ProgressPercentage
        Case 0
            For Each dr As Fattura In DataGridFatture.DataSource
                If (dr.Stato <> Fattura.Semaforo.STAMPATO) Then
                    dr.Stato = Fattura.Semaforo.INATTESA
                    dr.Icon = My.Resources.Waiting_icon
                    DataGridFatture.Refresh()
                End If
            Next
        Case 1
            For Each dr As Fattura In DataGridFatture.DataSource
                If (dr.Path = pathDoc) Then
                    dr.Stato = Fattura.Semaforo.STAMPATO
                    dr.Icon = My.Resources.Ok_Icon
                    DataGridFatture.Refresh()
                End If
            Next
        Case 2
            For Each dr As Fattura In DataGridFatture.DataSource
                If (dr.Stato = Fattura.Semaforo.INSTAMPA Or dr.Stato = Fattura.Semaforo.INATTESA) Then
                    dr.Stato = Fattura.Semaforo.ANNULLATO
                    dr.Icon = My.Resources.Cancel_icon
                    DataGridFatture.Refresh()
                End If
            Next
        Case 3
            For Each dr As Fattura In DataGridFatture.DataSource
                If (dr.Path = pathDoc) Then
                    dr.Stato = Fattura.Semaforo.INSTAMPA
                    dr.Icon = My.Resources.Print_icon
                    DataGridFatture.Refresh()
                End If
            Next
        Case 4
            btnCancelPrint.Enabled = True
        Case 5
            btnPrint.Enabled = True
    End Select
End Sub

Private Sub btnDown_Click(sender As Object, e As EventArgs) Handles btnDown.Click
    If (bs.Count <= 1) Then Return

    Dim position As Integer = bs.Position
    If (position = bs.Count - 1) Then Return

    bs.RaiseListChangedEvents = False

    Dim current As Fattura = bs.Current
    bs.Remove(current)

    position = position + 1

    bs.Insert(position, current)
    bs.Position = position

    bs.RaiseListChangedEvents = True
    bs.ResetBindings(False)
End Sub

【问题讨论】:

通常你的 DGV 数据源是一个 dt(数据表)。因此,而不是 DataGridFatture.Refresh() 将 DGV DataSource 设置为 Nothing 然后返回原始 DataSource : DataGridView1.DataSource = Nothing, DataGridView1.DataSource = dt 主要问题是当我单击按钮移动列表中的文件时。我正确更改了 DGV 中的位置,但在 for each 循环中出现错误:“集合已更改。可能无法执行枚举操作” 将我的代码放在 FOR 循环之后,它只需要运行一次。最好把它放在 SELECT 之后。您不需要在每个 Case 语句中使用它。 【参考方案1】:

问题在于数据网格不属于后台进程,但它属于另一个进程,即您的表单。 后台进程有自己的资源,不能直接访问表单控件! 无论如何,尝试:

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false

但是注意,这条指令违反了安全策略。

【讨论】:

我知道这种方法,但我不能在我的应用程序中使用它,所以我正在寻找另一种解决方案。

以上是关于如何使用 BackGroundWorker 刷新 DataGridView的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# BackgroundWorker 报告本机 C++ 代码的进度?

如何正确实现 BackgroundWorker 以通知用户任务正在进行中

BackgroundWorker,我怎样才能显示真正的进步? C# Winforms

如何使 Backgroundworker 中的进程在 Cancellation Pending 事件中退出

如何在点击触发的backgroundWorker中添加一段代码?

如何在窗体的关闭事件中停止 BackgroundWorker?