通过BackgroundWorker更新GridView完成使网格不是交互式的

时间:2013-09-25 08:06:04

标签: vb.net gridview backgroundworker

我正在尝试在完成BackgroundWorker时更新GridView,这是第一次正常工作,但是如果再次尝试执行worker,数据将被分配给网格,但我无法在UI级别的GridView上选择一行现在还显示了垂直滚动。如果尝试多次双击单元格,则会出现垂直滚动,我可以选择任何行。

enter image description here

请参阅VB.Net代码

Public Class Form1

Dim Workers() As BackgroundWorker

Dim dtCustomers As DataTable = New DataTable()
Private dtCustomersLock As New Object
Private dgvCustomersLock As New Object

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    dtCustomers.Columns.Add("CustomerID")
    dtCustomers.Columns.Add("CustomerName")
    dtCustomers.Columns.Add("Age")
    LoadWorkers()
End Sub

Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
    btnClear_Click(sender, e)

    loadCustomerGrid()
    UpdateCustomerGrid()
End Sub

Private Sub LoadWorkers()
    ReDim Workers(1)

    Workers(1) = New BackgroundWorker
    Workers(1).WorkerReportsProgress = True
    Workers(1).WorkerSupportsCancellation = True
    AddHandler Workers(1).DoWork, AddressOf loadCustomerGrid
    AddHandler Workers(1).RunWorkerCompleted, AddressOf UpdateCustomerGrid
End Sub

Private Sub btnLoadThread_Click(sender As Object, e As EventArgs) Handles btnLoadThread.Click

    If Not Workers(1).IsBusy Then
        dtCustomers.Clear()
        Workers(1).RunWorkerAsync()
    End If
End Sub

Private Sub loadCustomerGrid()

    SyncLock dgvCustomersLock
        For i As Integer = 0 To 10
            dtCustomers.Rows.Add(i, "Customer" + i.ToString(), "20" + i.ToString())
        Next
    End SyncLock

    Threading.Thread.Sleep(100)
End Sub

Private Sub UpdateCustomerGrid()
    SyncLock dtCustomersLock
        DataGridView1.DataSource = dtCustomers
        DataGridView1.Focus()
    End SyncLock
End Sub

Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
    dtCustomers.Clear()
End Sub
End Class

1 个答案:

答案 0 :(得分:1)

因为您正在从Worker线程访问UI线程的DataGridView1,所以您会得到奇怪的行为。

我用这段代码测试了你的小应用程序,我得到了正常的预期行为。

我修改了你的loadCustomerGrid方法并添加了另一个Method and Delegate方法。

 Private Sub loadCustomerGrid()

    SetDataGrid(GridView1)
    Threading.Thread.Sleep(100)
End Sub
 Private Sub setDataGrid(ByVal grd As DataGridView)
    If grd.InvokeRequired Then
        grd.Invoke(New setDataGridInvoker(AddressOf setDataGrid), grd)
    Else
        For i As Integer = 0 To 10
            dtCustomers.Rows.Add(i, "Customer" + i.ToString(), "20" + i.ToString())
        Next
    End If
End Sub
Private Delegate Sub setDataGridInvoker(ByVal grd As DataGridView)

说明:

“从工作线程安全访问控件的方法是通过委托。首先测试控件的InvokeRequired属性,它将告诉您是否可以安全地访问控件.InvokeRequired是少数几个成员之一控制类是线程安全的,所以你可以在任何地方访问它。如果属性为True,则需要调用来访问控件,因为当前方法是在拥有控件的Handle的线程以外的线程上执行。

通过调用控件的Invoke或BeginInvoke方法来执行调用。您创建一个委托,该委托是一个包含对方法的引用的对象。最好将其作为对当前方法的引用。然后,您将该委托传递给Invoke或BeginInvoke方法。这将基本上再次调用引用的方法,这次是在拥有控件的Handle的线程上。“

来源:jmcilhinney发布从工作线程访问控件http://www.vbforums.com/showthread.php?498387-Accessing-Controls-from-Worker-Threads