如何使用 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 事件中退出