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