標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

バックグラウンドワーカーからダイアログのデータを更新する

(2020.02.25 追記あり

通常は BackgroundWorker からダイアログのコントロールを操作することはできない。だが、Delegate を経由すれば、可能になる。

Public Class Form1
    '*** UIスレッドで実行される関数 ***
    Private Sub AddRow(color1 As Color, objs As Object())
        Dim row1 As New DataGridViewRow
        row1.CreateCells(Me.DataGrid_Sheet)
        For i As Integer = LBound(objs) To UBound(objs)
            row1.Cells(i).Value = objs(i)
        Next
        row1.DefaultCellStyle.BackColor = color1
        row1.Resizable = DataGridViewTriState.False
        Me.DataGrid_Sheet.Rows.Add(row1)
    End Sub

    '*** UIスレッドへ、更新データを送る Delegate の宣言
    Delegate Sub AddRowDelegate(color1 As Color, objs As Object())
    Private AddRowDelegate1 As New AddRowDelegate(AddressOf AddRow)

   '*** バックグラウンドワーカー
    Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
   '            : 中略
                Me.Invoke(AddRowDelegate1,
                    color,
                    New Object() { 
                        ' セルデータ,
                    }  )
  '            : 中略
    End Sub

ただし、あまりにも更新のスピードが多いと、U/I スレッドがそれへの応答でいっぱいいっぱいになって応答がなくなってしまい、BackgroundWorker の意味がなくなってしまう。

そのような場合、結局、タイマ割り込みで休み休みやった方が安全のようだ。(このあたりは推測にすぎないが…)

(2020.02.25 追記)

本記事では、当初、次のように書いていた。

Me.AddRowDelegate1.Invoke(
    color,
    New Object() { 
            ' セルデータ,
            }  )

だが、Windowsフォームで別スレッドからコントロールを操作するには?:.NET TIPS - @ITによると、コントロールのメソッドとして呼ばないと、意味がないようだ(そりゃそうだ)

Me.Invoke(
    AddRowDelegate1,
    color,
    New Object() { 
           ' セルデータ,
    }  )

また、Invoke はメインスレッドをブロックするが、BeginInvoke だと待機状態になったタイミングで実行するとあるので、BeginInvokeを使えば U/I スレッドがいっぱいいっぱいになることは避けられるかもしれない