我有一个带有DataGridView的应用程序,多个人可以同时在上面工作。我想通过DataGridView中的不同颜色行显示每个用户的当前行位置。
以前,我是通过RowEnter
事件进行所有此更新的,但是由于明显的原因,性能并不令人满意。
我正在尝试创建一个背景线程,该线程每10秒循环一次,以用其他用户所在位置的键填充DataTable,然后该键引用DGV中的键列,如果匹配,则更改DGV行的背景色否则将其设置为默认值。
下面我的当前代码每10秒钟循环一次,但实际上并没有更新DGV。
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ActiveThread = True
dgvThread = New Thread(AddressOf UpdateDGVFromThread) With {
.IsBackground = True}
dgvThread.Start()
End Sub
Public Sub UpdateDGVFromThread()
Do While ActiveThread = True
'Sets table with key values
dtUsers = CLS_USERS.GetUsers(User)
'Loop through them
For Each row As DataRow In dtUsers.Rows
intSeq = row("SEQUENCE")
'Loop through each DGV row and compare the values
For Each dgv_row As DataGridViewRow In dgvCandList.Rows
dgvCandList.BeginInvoke(
Sub()
If dgv_row.Cells("CURRENT_CAND_SQ").Value = intSeq Then
dgv_row.DefaultCellStyle.BackColor = Color.DarkCyan
Else
dgv_row.DefaultCellStyle.BackColor = Color.Cyan
End If
End Sub)
Next
Next
Thread.Sleep(10000)
Loop
End Sub
我尝试使用 dgv.Invoke()
而不是 .BeginInvoke()
,但这似乎不断锁定UI线程,并且只有DGV被解锁。 / p>
有人能指出我正确的方向吗?
答案 0 :(得分:1)
BeginInvoke方法用于在创建控件的句柄的线程上异步调用方法委托。 UI线程,在这里。它的签名是:
Public Function BeginInvoke (method As Delegate) As IAsyncResult
然后在创建被调用的控件的同一线程中声明 method
。
然后应该这样声明委托:
在用户界面线程中:
Delegate Sub MyUpdateDelegate()
Public Sub MyUpdateMethod()
[SomeControl].Text = "Updated Text"
End Sub
在另一个线程中:
Private Sub InvokeFromAnotherThread()
'(...)
[SomeControl].BeginInvoke(New MyUpdateDelegate(AddressOf MyUpdateMethod))
'Or
Me.BeginInvoke(New MyUpdateDelegate(AddressOf MyUpdateMethod))
'(...)
End Sub
就地使用匿名方法不会削减它。
MethodInvoker代表提供了一个快捷方式:
MethodInvoker提供了一个简单的委托,用于调用 参数列表无效的方法。此委托可以在以下情况下使用 调用控件的Invoke方法或需要简单的方法 委托,但不想自己定义。
使用MethodInvoker
委托,无需在UI线程中声明委托。可以在此处使用匿名方法,它将在UI线程中调用:
Private Sub InvokeFromAnotherThread()
'(...)
BeginInvoke(New MethodInvoker(Sub() [SomeControl].Text = "Updated Text"))
'(...)
End Sub
或者:
Private Sub InvokeFromAnotherThread()
'(...)
BeginInvoke(New MethodInvoker(
Sub()
[SomeControl].Text = "Updated Text"
[SomeOtherControl].BackColor = Color.Red
End Sub))
'(...)
End Sub
为什么我建议使用计时器:
您正在使用的线程只有一项任务:更新UI线程中的Control,然后休眠。
要执行此任务,它需要在UI线程中调用一个方法。如果创建线程的原因是避免阻塞UI线程,则Timer将执行相同的操作。具体来说,System.Windows.Forms.Timer
将在UI线程中引发其Tick
事件,而无需跨线程调用。
实际效果大致相同。