5

I understand that .NET is multi-threaded and that is a good thing, but I continually run into issues when I have a background worker for example that is updating some control on my form and I have to do:

Private Sub SetRowCellBoolValueThreadSafe(ByVal row As Integer, ByVal col As Integer, ByVal value As Boolean)
    If dgvDatabase.InvokeRequired Then
        Dim d As New SetRowCellBoolValueCallback(AddressOf SetRowCellBoolValue)
        Me.Invoke(d, New Object() {row, col, value})
    Else
        SetRowCellBoolValue(row, col, value)
    End If
End Sub

Delegate Sub SetRowCellBoolValueCallback(ByVal row As Integer, ByVal col As Integer, ByVal value As Boolean)

Private Sub SetRowCellBoolValue(ByVal row As Integer, ByVal col As Integer, ByVal value As Boolean)
    dgvDatabase.Rows(row).Cells(col).Value = value
End Sub

My question is why is this not built into the framework - surely if I am trying to update a DataGridView it should be intelligent enough to know when the update is from another thread and it could do all the above itself?

Matt Wilko
  • 26,994
  • 10
  • 93
  • 143

3 Answers3

6

The would mean turning every operation on a UI control into a delegate, just in case it needed to be marshalled to a different thread. That would be hugely expensive. Additionally, it presupposes that you always want to do the same thing - use Invoke rather than BeginInvoke for example.

I agree it's a bit of a pain in the neck to have to do this manually, but the next versions of C# and VB should make life a lot easier with async methods.

(As an aside, I don't think you really want to use ByRef for all those parameters... is it possible that you're not really clear what ByRef means?)

Rune FS
  • 21,497
  • 7
  • 62
  • 96
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Is it difficult to identify either the call is actually comes from another thread and only that ones pass to delegate? – Tigran Sep 01 '11 at 09:05
  • 1
    +1 for the side note. Must be painful to use `ByRef` everywhere. – jgauffin Sep 01 '11 at 09:05
  • @Tigran: It's not difficult, but you'd need the code to *build* the delegates everywhere. If you work from the assumption that only the UI thread should touch the controls, it's hard to see how you can keep that cheap without having huge amounts of crufty (even if generated) code. – Jon Skeet Sep 01 '11 at 09:07
  • @Jon: I was thinking about the code injected by compiler and not generated by me like a coder. I mean even if the compiler have to inject some tricky code and it doesn't affect too much the final performance of my app, it will leave my code clear without anoying calls to delegates or whatever and continue working in multithreaded environment. Sure "async" will make a life much easier from this perspective. – Tigran Sep 01 '11 at 09:11
  • 1
    @Tigran: So that makes the *language* more complicated - and it could very well affect the final performance significantly. Every bit of UI code would be much larger, affecting cache coherence, inlining etc. – Jon Skeet Sep 01 '11 at 09:17
1

I don't work for Microsoft but I would guess,

Most GUI code written with .NET is not Multi-threaded so, why incur the burden of checking for the minority case. The developer should know it there is a potential for multi-threading and check when appropriate.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
1

In the specific case of a BackgroundWorker, I would suggest you use its progress reporting feature.

Your BackgroundWorker calls ReportProgress, optionally passing an object with some state information. This raises the ProgressChanged event on the UI thread, which can update controls on your form, using the state information passed from the background worker.

Progress reporting is not limited to updating a ProgressBar or similar.

Joe
  • 122,218
  • 32
  • 205
  • 338