Link to home
Avatar of rogerard
rogerardFlag for United States of America

asked on

Threading Problem Updating Datatable and Refreshing DataGridView

I have a DataGridView (dgv) whose DataSource is a BindSource Control whose DataSource is a Dataset and DataMember is a DataTable (dtMain).
 
Private Delegate sub AddEntryToTableCallback(Byval Entry as SearchResultEntry)

Private Sub bwWorker_DoWork(ByVal sender as Object, ByVal e as DoWorkEventArgs) Handles bwWorker.DoWork
  

  Dim AddEntry As New AddEntryToTableCallback(AddressOf AddEntryToTable)

  '...
  '.... Some worker code here...'
  '...

  While True

    For Each entry as SearchResultEntry in Response.Entries
      AddEntry.Invoke(entry)
    Next

  End While

End Sub

Private Sub AddEntryToTable(ByVal Entry as SearchResultEntry)
  Dim tmpDataRow as DataRow = dtMain.NewRow

  '..Assign values to datarow....'

  dtMain.Rows.Add(tmpDataRow)
  dtMain.AcceptChanges()

  if Me.InvokeRequired Then
    Me.BeginInvoke(New MethodInvoker(AddressOf RefreshDisplay))
  Else
    RefreshDisplay()
  End If
End Sub

Private Sub RefreshDisplay()

    If me.InvokeRequired Then
      me.Invoke(New MethodInvoker(AddressOf dgv.Refresh))
    Else
      dgv.Refresh
    End If

End Sub

Open in new window

If I manipulate dgv too much (ie resize, scroll through the added results) while it's still adding, I'll get several of these errors:
 
DataGridView Default Error Dialog

The following exception occured in the DataGridView:

System.InvalidOperationException:  BindingSource cannot be its own data source.  Do not set the DataSource and Datamember Properties to values that refer back to the BindingSource.
  at System.Windows.Forms.BindingSource.get_Count()
  at System.Windows.Forms.CurrencyManager.get_Item(Int32_index)
  at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)

To replace this default dialog please handle the DataError Event.

Open in new window

It isn't exactly clear where this is getting thrown and I've tried adding a catch for the DataError Event, but I can't Isolate it.  The error doesn't seem to hinder the results from continuing to be added.  Nor does the error occur at any time after all rows have been added.  

Does anyone have any thoughts how I can catch and handle/ignore the error?

Thanks
Avatar of Nasir Razzaq
Nasir Razzaq
Flag of United Kingdom of Great Britain and Northern Ireland image

Try handling the DataError event of both BindingSource and the grid.
as above,  handle the datagridview dataerror event. the errors will not simply go away, you can "diagonise" their source/ cause there too
Avatar of rogerard

ASKER

The answer was right in front of me, in the original error message.  Thanks for pointing it out!  Based on your suggestions, I added the following code:
 
Private Sub bs_DataError(ByVal sender As Object, ByVal e As BindingManagerDataErrorEventArgs) Handles bs.DataError

  Debug.WriteLine("bs_DataError" & NewLine() & vbTab & e.Exception.Message)

End Sub

Private Sub dgv_DataError(ByVal sender As Object, ByVal e As DataGridViewDataErrorEventArgs) Handles dgv.DataError

  If e.Exception.Message.Contains("BindingSource cannot be its own data source") Then
    e.ThrowException = False 'Threading issue..  data still good'
  Else
    Debug.WriteLine("dgvADSI_DataError" & NewLine() & vbTab & e.Exception.Message)
  End If

End Sub

Open in new window

Those errors are now handled.  But a new/related problem seems to have arisen that I can't seem to diagnose.  If I run the executable outside the IDE, it hangs at the point where the vertical scrollbar gets added to dgv, after adding the 7th row to dtMain.  I attached to the process from the IDE and it's hanging at line 42 of the original code I posted.
dgv.Refresh

Open in new window

Any thoughts?
Does it execute that line successfully when run from the VS?
Yes, the code appears to run flawlessly from within the IDE, in so far that there are no unhandled exceptions displayed.
That is strange. Try enclosing it in Try Catch block.
I didn't put it in the code posted above for brevity, but the original code already contains:
Try 
 '......'
Catch ex as Exception
  MsgBox(ex.Message)
Finally
 'Cleaning up resources here'
End Try

Open in new window

The exception is never getting triggered.
I changed
Private Sub RefreshDisplay()

    If me.InvokeRequired Then
      me.Invoke(New MethodInvoker(AddressOf dgv.Refresh))
    Else
      dgv.Refresh
    End If

End Sub

Open in new window

to
Private Sub RefreshDisplay()

    If me.InvokeRequired Then
      me.Invoke(New MethodInvoker(AddressOf dgv.Invalidate))
    Else
      dgv.Invalidate
    End If

End Sub

Open in new window

Now, it doesn't hang after the 7th row, it'll continue adding.  That is, until I try to resize the form, which resizes the dgv, which causes it to hang (outside the IDE, inside in debug mode still runs normal).
When I attach to process and pause execution, it doesn't show me the green/yellow arrow designating the line it's paused on, so I'm at a loss.
Try using SuspendLayout and ResumeLayout functions.
I made the following changes.  Now it hangs on line 12 after the 7th row is added.
Private Delegate Sub RefreshCallback(ByVal performLayout As Boolean)

Private Sub RefreshDisplay()

    If me.InvokeRequired Then
        Me.Invoke(New MethodInvoker(AddressOf dgv.SuspendLayout))
        Me.Invoke(New MethodInvoker(AddressOf dgv.Invalidate))
        Me.Invoke(New RefreshCallback(AddressOf dgv.ResumeLayout), True)
    Else
        dgv.SuspendLayout()
        dgv.Invalidate()
        dgv.ResumeLayout(True)
    End If

End Sub

Open in new window

Suspend and Resume layout is used around any operation which is modifying the grid. So

dgv.SuspendLayout)
dgv.Rows.Add(...)
dgv.Rows(0).Cells(0).Value = ...
dgv.ResumeLayout(True)
ASKER CERTIFIED SOLUTION
Avatar of rogerard
rogerard
Flag of United States of America image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
None of the suggestions provided actually resolved the problem.  I figured out the solution myself.