在后台线程上更新DataGridView.BackColor

时间:2019-01-23 09:16:28

标签: vb.net multithreading winforms datagridview

我有一个带有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>

有人能指出我正确的方向吗?

1 个答案:

答案 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事件,而无需跨线程调用。 实际效果大致相同。