A DataGridView
является элементом пользовательского интерфейса - вам не разрешен доступ к нему из любого потока, кроме пользовательского интерфейса. Вы не можете использовать Parallel.ForEach
на нем.
Что вы можете сделать, это извлечь данные как объект без пользовательского интерфейса, параллельно работать над этим, а затем присвоить результаты обратно.
Попробуйте это:
'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
.MachineName = dgvrow.Cells(0).Value,
.ServiceName = dgvrow.Cells(1).Value
}).ToArray()
'Parallel
Dim serviceControllers = inputs.AsParallel().Select(Function (x) New ServiceController With _
{
.MachineName = x.MachineName,
.ServiceName = x.ServiceName
}).ToArray()
'UI thread
For Each x In serviceControllers.Zip(DataGridView1.Rows.Cast(Of DataGridViewRow), Function (sc, dgvrow) New With { sc, dgvrow })
x.dgvrow.Cells(2).Value = x.sc.Status.ToString
Next
Используйте это, если строки изменяют порядок во время вычисления.
'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
.MachineName = dgvrow.Cells(0).Value,
.ServiceName = dgvrow.Cells(1).Value,
.dgvrow = dgvrow
}).ToArray()
'Parallel
Dim results = inputs.AsParallel().Select(Function (x) New With
{
.sc = New ServiceController With _
{
.MachineName = x.MachineName,
.ServiceName = x.ServiceName
}, _
.dgvrow = x.dgvrow
}).ToArray()
'UI thread
For Each x In results
x.dgvrow.Cells(2).Value = x.sc.Status.ToString
Next
Имейте в виду, если строки будут удалены во время вычислений, это также не удастся.
Вы должны использовать Microsoft Reactive Framework (он же Rx) - NuGet System.Reactive.Windows.Forms
и добавить using System.Reactive.Linq;
- тогда вы можете сделать это:
'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
.MachineName = CType(dgvrow.Cells(0).Value, String),
.ServiceName = CType(dgvrow.Cells(1).Value, String),
.Row = dgvrow
}).ToArray()
'Rx query
Dim query = _
From x In inputs.ToObservable()
From s In Observable.Start(Function () FetchStatus(x.MachineName, x.ServiceName))
Select New With
{
x.Row,
.Status = s
}
'Rx subscription
Dim subscription As IDisposable = _
query _
.ObserveOn(DataGridView1) _
.Subscribe(Sub (x) x.Row.Cells(2).Value = x.Status)
Это обновит каждую строку, как только ответ вернется, и будет обрабатываться параллельно.
Я предположил, что у вас есть функция с такой подписью: Function FetchStatus(MachineName As String, ServiceName As String) As String
.