Task.WaitAll () в событии DataGridView.RowEnter вызывает DataError - PullRequest
0 голосов
/ 06 ноября 2019

Я использую Advanced DataGridView (https://github.com/davidegironi/advanceddatagridview) для отображения некоторых данных в моем приложении.

В событии RowEnter я создаю такие задачи:

Dim One As String = dgv.Item("Col1", e.RowIndex)
Dim Two As String = dgv.Item("Col2", e.RowIndex)
Dim Three As String = dgv.Item("Col3", e.RowIndex)

Dim tOne As Task(Of DataTable) = Task.Run(Function() Return GetData(One) End Function)
Dim tTwo As Task(Of DataTable) = Task.Run(Function() Return GetData(Two) End Function)
Dim tThree As Task(Of DataTable) = Task.Run(Function() Return GetData(Three) End Function)

Task.WaitAll(tOne, tTwo, tThree)

'Do stuff with the results of tasks to update other labels etc on the form
lblDate.Text = tOne.Result.Rows(0).Item("Date").ToString

Причинаэто потому, что если функция GetData() займет, скажем, 5 секунд, чтобы вернуться, то без выполнения задач это приведет к 15-секундному ожиданию (5 + 5 + 5), тогда как для задач это займет всего 5 секунд (или что-то самое медленное). is) и Task.WaitAll возвращает управление обратно в UI (неуверен в правильной терминологии), поэтому он чувствует себя немного более резким.

Однако, когда я применяю фильтр, я повторно получаю следующее исключение, где [n] - любое число, Я видел индексы от -1 вверх (кажется, зависит от количества видимых строк?):

System.IndexOutOfRangeException: Index [n] does not have a value.
   at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
   at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)

Если я удаляю Task.WaitAll () или выполняю функции синхронно, я не делаюполучите вышеупомянутую ошибку.

Я полностью в недоумении относительно того, что является основной причиной этой ошибки, или что я должен сделать иначе, чтобы ее избежать.

Я видел этот ответ но я неуверен, как применить к моей ситуации.

1 Ответ

1 голос
/ 06 ноября 2019

Используйте обработчик асинхронных событий и ожидайте задачи, используя Task.WhenAll

' Mark the event handler with Async so you can use Await in it.
Private Async Sub Grid_RowEnter(sender As Object, e As WhateverEventArgs)
    Dim One As String = dgv.Item("Col1", e.RowIndex)
    Dim Two As String = dgv.Item("Col2", e.RowIndex)
    Dim Three As String = dgv.Item("Col3", e.RowIndex)

    Dim tOne As Task(Of DataTable) = Task.Run(Function() Return GetData(One) End Function)
    Dim tTwo As Task(Of DataTable) = Task.Run(Function() Return GetData(Two) End Function)
    Dim tThree As Task(Of DataTable) = Task.Run(Function() Return GetData(Three) End Function)

    ' await all the tasks
    Await Task.WhenAll(tOne, tTwo, tThree)

    ' back on UI thread

    'Do stuff with the results of tasks to update other labels etc on the form
    lblDate.Text = tOne.Result.Rows(0).Item("Date").ToString

End Sub

Ссылка Асинхронное / ожидание - лучшие практики асинхронного программирования

...