Обновление DataGridView.BackColor в фоновом потоке - PullRequest
0 голосов
/ 23 января 2019

У меня есть приложение с 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(), но это, казалось, постоянно блокировало поток пользовательского интерфейса, и только DGV был разблокирован.

Кто-нибудь может указать мне правильное направление?

1 Ответ

0 голосов
/ 23 января 2019

Метод BeginInvoke используется для асинхронного вызова делегата метода в потоке, который создал дескриптор элемента управления.Поток пользовательского интерфейса здесь.Его подпись:

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 предоставляет простой делегат, который используется для вызова метода со списком параметров void.Этот делегат может использоваться при вызове метода Invoke элемента управления или когда вам нужен простой делегат, но вы не хотите определять его самостоятельно.

Используя делегат MethodInvoker, нет необходимостиобъявить делегата в потоке пользовательского интерфейса.Здесь можно использовать анонимный метод, он будет вызываться в потоке пользовательского интерфейса:

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

Почему я предложил таймер:
В используемом вами потоке есть только одна задача: обновить элемент управления в потоке пользовательского интерфейса, а затем перевести в спящий режим.
Для выполнения этой задачи необходимо вызвать метод в потоке пользовательского интерфейса.Если причина, по которой поток был создан, состоит в том, чтобы избежать блокировки потока пользовательского интерфейса, таймер будет делать то же самое.В частности, System.Windows.Forms.Timer вызовет событие Tick в потоке пользовательского интерфейса без вызовов между потоками.Практический эффект более или менее одинаков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...