代码之家  ›  专栏  ›  技术社区  ›  Tharik Kanaka

通过BackgroundWorker完成更新GridView使网格不具有交互性

  •  1
  • Tharik Kanaka  · 技术社区  · 13 年前

    我正在尝试在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 回复  |  直到 13 年前
        1
  •  1
  •   UrsulRosu    13 年前

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

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

    我修改了您的loadCustomerGrid方法,并添加了另一个method和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是control类中为数不多的线程安全成员之一,因此您可以在任何位置访问它。如果该属性为True,则需要调用来访问控件,因为se当前方法在一个线程上执行,而不是在拥有控件的Handle的线程上执行。

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

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

    推荐文章