未捕获共享/静态数据源的跨线程更新

时间:2013-02-08 11:46:31

标签: vb.net winforms .net-4.0 datagridview

我有一个共享/静态 DataTable ,可以在整个应用程序中访问。 在表单上,我有 DataGridView 绑定到 DataTable DataView 。 我的问题是 DataTrid 的跨线程更新没有被 DataGridView 捕获,尽管基础数据源(DataView)已更新。

我已经尝试了 DataGridView 的更新,无效,刷新和重置绑定方法,但仍然没有添加,删除或更新行。

'The following example requires:
'-----------------------------------------------------------------------------
'Friend WithEvents DataGridView1 As System.Windows.Forms.DataGridView
'Friend WithEvents Button1 As System.Windows.Forms.Button
'Friend WithEvents Button2 As System.Windows.Forms.Button
'Friend WithEvents BackgroundWorker1 As System.ComponentModel.BackgroundWorker
'-----------------------------------------------------------------------------

Public Class Form1

    Shared Sub New()
        Repository = New DataTable()
    End Sub

    Public Sub New()
        Me.InitializeComponent()
        Me.view = New DataView(Repository)
        Me.DataGridView1.DataSource = Me.view
    End Sub

    'Updates the DataGridView correctly.
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Using table As DataTable = GetUpdatedDataTable()
            SyncLock Repository
                Repository.Merge(table)
            End SyncLock
        End Using
    End Sub

    'Do NOT update the DataGridView correctly (cross-thread)
    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        If (Not Me.BackgroundWorker1.IsBusy) Then
            Me.BackgroundWorker1.RunWorkerAsync()
        End If
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Using table As DataTable = GetUpdatedDataTable()
            SyncLock Repository
                Repository.Merge(table)
            End SyncLock
        End Using
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Me.DataGridView1.Update()
        Me.DataGridView1.Refresh()
        Me.DataGridView1.Invalidate(False)
        Me.DataGridView1.Invalidate(True)
        Me.DataGridView1.ResetBindings()
        MsgBox(Me.view.Count)
    End Sub

    Private Shared Function GetUpdatedDataTable() As DataTable
        Dim table As New DataTable("TEST")
        table.Columns.AddRange(New DataColumn() {New DataColumn("ID", GetType(Integer)), New DataColumn("TEXT", GetType(String))})
        table.Rows.Add(Repository.Rows.Count, String.Format("Row #{0}", Repository.Rows.Count))
        table.AcceptChanges()
        Return table
    End Function

    Public Shared Repository As DataTable
    Private ReadOnly view As DataView

End Class'

2 个答案:

答案 0 :(得分:0)

您应该尝试以下方式而不是刷新:

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Me.DataGridView1.Update()
            Me.DataGridView1.DataSource = Nothing
            Me.DataGridView1.DataSource = Repository           
            Me.DataGridView1.Invalidate(False)
            Me.DataGridView1.Invalidate(True)
            Me.DataGridView1.ResetBindings()
            MsgBox(Me.view.Count)
        End Sub

答案 1 :(得分:0)

由于这个问题很快就要庆祝它的第一个“生日”,所以最好还是给它一个最终答案。 DataGridView未更新的原因是因为DataView.ListChanged事件(DGV挂钩)在工作线程而不是UI线程上引发。

选项1

在UI线程上进行合并。

Me.Invoke(Sub() Repository.Merge(table))

当然,这将冻结应用程序,直到合并完成。

选项2

DataView进行子类化,并使其能够在需要时引发ListChanged事件。

Public Class DataViewEx
    Inherits DataView

    Public Sub New()
    End Sub

    Public Sub New(table As DataTable)
        MyBase.New(table)
    End Sub

    Public Sub New(table As DataTable, rowFilter As String, sort As String, rowState As DataViewRowState)
        MyBase.New(table, rowFilter, sort, rowState)
    End Sub

    Public Sub Refresh()
        Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
    End Sub

End Class

现在,一旦工作人员完成了任务,所有人必须做的就是调用Refresh方法,而DataGridView “与{同步” {1}}。

DataView