Solved

DataGridView InvalidOperationException

Posted on 2010-11-12
9
655 Views
Last Modified: 2012-05-11
I have a datagridview whose datasource is a bindingsource linked to a datatable in a dataset.

From a background worker, I want to add rows to the table then refresh the datagridview to reflect the updates.

Here's what I have so far:
 
Private Delegate Sub AddEntryCallback(ByVal Entry As SearchResultEntry)
  Private Delegate Sub RefreshDisplayCallback()

  Private Sub bwPageSearch_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwPageSearch.DoWork
     
'.....'

      Dim AddEntry As AddEntryCallback = AddressOf AddEntryToTable
      Dim UpdateDisplay As RefreshDisplayCallback = AddressOf RefreshDisplay

'.....'

          For Each entry As SearchResultEntry In Response.Entries
            If dgvADSI.InvokeRequired Then
              AddEntry.Invoke(entry)
            Else
              AddEntryToTable(entry)
            End If
            If dgvADSI.InvokeRequired Then
              UpdateDisplay.Invoke()
            Else
              RefreshDisplay()
            End If
          Next

'.....'

  End Sub

  Private Sub AddEntryToTable(ByVal Entry As SearchResultEntry)

    Try
      Dim tmpDataRow As DataRow = dtADSI.NewRow

      If Entry.Attributes.Contains("displayname") Then tmpDataRow.Item("Name") = Entry.Attributes.Item("displayname").Item(0).ToString
      If Entry.Attributes.Contains("mail") Then tmpDataRow.Item("E-Mail Address") = Entry.Attributes.Item("mail").Item(0).ToString
      If Entry.Attributes.Contains("telephonenumber") Then tmpDataRow.Item("Business Phone") = Entry.Attributes.Item("telephonenumber").Item(0).ToString
      If Entry.Attributes.Contains("homephone") Then tmpDataRow.Item("Home Phone") = Entry.Attributes.Item("homephone").Item(0).ToString
      If Not String.IsNullOrEmpty(Entry.DistinguishedName.Trim) Then tmpDataRow.Item("adsPath") = Entry.DistinguishedName.ToString
      dtADSI.Rows.Add(tmpDataRow)
      dtADSI.AcceptChanges()
      tmpDataRow = Nothing
    Catch ex As Exception
      MsgBox("AddEntryToTable: " & NewLine() & ex.Message)
    End Try

  End Sub 

  Private Sub RefreshDisplay()

    Try
      If dtADSI.Rows.Count > 0 Then
        Try
          If Not dgvADSI.Visible Then
            'Cross-thread errors happen on any of these lines of code'
            Me.MaximumSize = New Size(intResultsMaxFrmWt, intResultsMaxFrmHt)
            Me.MinimumSize = New Size(intResultsFrmWt, intResultsFrmHt)
            dgvADSI.AutoResizeColumns()
            dgvAHCS.Visible = False
            dgvADSI.Visible = True
          End If
        Catch ex As Exception
          MsgBox("Not dgvADSI.Visible: " & NewLine() & ex.Message)
        End Try
        dtADSI.AcceptChanges()
        Try
          dgvADSI.Invalidate()
        Catch ex As Exception
          MsgBox("dgvADSI.Invalidate: " & NewLine() & ex.Message)
        End Try
      End If
    Catch ex As Exception
      MsgBox("dtADSI.Rows.Count: " & NewLine() & ex.Message)
    End Try

  End Sub

Open in new window


Problem is, I'm getting Cross-thread errors when the code tries to resize the form or modify the datagridview.  I know that the section of code is being invoked, due to debugging I've put in.  What am I missing and need to do to get this to work?
0
Comment
Question by:rogerard
  • 7
  • 2
9 Comments
 
LVL 7

Author Comment

by:rogerard
ID: 34123056
I've made some progress:

I've replaced  
Me.MaximumSize = New Size(intResultsMaxFrmWt, intResultsMaxFrmHt)
Me.MinimumSize = New Size(intResultsFrmWt, intResultsFrmHt)
dgvADSI.AutoResizeColumns()
dgvAHCS.Visible = False
dgvADSI.Visible = True

Open in new window

with  
updateUI(Me, "MaximumSize", New Size(intResultsMaxFrmWt, intResultsMaxFrmHt))
updateUI(Me, "MinimumSize", New Size(intResultsFrmWt, intResultsFrmHt))
dgvADSI.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
updateUI(dgvAHCS, "Visible", False)
updateUI(dgvADSI, "Visible", True)

Open in new window

Private Delegate Sub UpdateUICallback(ByVal ctrl As Control, ByVal prop As String, ByVal value As Object)
  
Private Sub updateUI(ByVal ctrl As Control, ByVal prop As String, ByVal value As Object)
    Try
      If ctrl.InvokeRequired = True Then
        Dim d As New UpdateUICallback(AddressOf updateUI)
        ctrl.Invoke(d, ctrl, prop, value)
      Else
        ctrl.GetType.GetProperty(prop).SetValue(ctrl, value, Nothing)
      End If
    Catch ex As Exception
      MsgBox(ex.Message)
    End Try
  End Sub

Open in new window

The invalidate didn't work, so I also replaced
dgvADSI.Invalidate
with
dgvADSI.Refresh()
Now, the crossthread error occurs on the refresh.  
0
 
LVL 7

Author Comment

by:rogerard
ID: 34123317
More progress.

I replaced
dgvADSI.Refresh()
With
ctlMethod(dgvADSI, "refresh")

Now, there's no exceptions, but the datagridview still is not refreshing.
Private Delegate Sub ctlMethodCallback(ByVal ctrl As Control, ByVal Method As String)
  Private Sub ctlMethod(ByVal ctrl As Control, ByVal Method As String)

    Try
      If ctrl.InvokeRequired Then
        Try
          Dim d As New ctlMethodCallback(AddressOf ctlMethod)
          ctrl.Invoke(d, ctrl, Method)
        Catch ex As Exception
          MsgBox("Unable to invoke: " & NewLine & ex.Message)
        End Try
      Else
        ctrl.GetType.GetMethod(Method)
      End If
    Catch ex As Exception
      MsgBox("Unable to appy method: " & NewLine & ex.Message)
    End Try

  End Sub

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34127869
When do you need to update the DataGridView?  If you need to update it after the BackgroundWorker is done, then I would make the call from the RunWorkerCompleted event.
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 7

Author Comment

by:rogerard
ID: 34128984
I'm trying to update the datagridview as the data is being added to the datatable.  I suspect it has something to with making the datatable sync information across threads, but I'm not sure how to do that.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34129093
How many rows are you getting for the DataGridView?  Is this a long running process, and you want to refresh the DataGridView after each "block" of data?
0
 
LVL 7

Author Comment

by:rogerard
ID: 34129222
On narrow queries, the results return and populate quickly.  On the broader queries, it can take up to a minute.   I'm trying to replicate, somewhat, the people search form when you click start>Search>People to add a few more capabilities and search locations specific to my company.  I have a active directory search set up using s.ds.p and returning paged results within a background worker, with a page size of 10, for results up to several thousand, possibly, depending on the search criteria.   I'm just not able to get the thread to update the dataset and refresh the datagridview the same way that the MS people search does on large results.

0
 
LVL 7

Assisted Solution

by:rogerard
rogerard earned 0 total points
ID: 34138550
I think I figured it out finally. Here's my final code.


Private Delegate Sub RefreshInvoker()
  Private Delegate Sub AutoResizeColumnsInvoker()

  Private Sub bwPageSearch_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwPageSearch.DoWork
          
          '........'

          For Each entry As SearchResultEntry In Response.Entries
            AddEntryToTable(entry)
          Next

          '........'

End sub

  Private Sub AddEntryToTable(ByVal Entry As SearchResultEntry)

    Try
      Dim tmpDataRow As DataRow = dtADSI.NewRow
      If Entry.Attributes.Contains("displayname") Then tmpDataRow.Item("Name") = Entry.Attributes.Item("displayname").Item(0).ToString
      If Entry.Attributes.Contains("mail") Then tmpDataRow.Item("E-Mail Address") = Entry.Attributes.Item("mail").Item(0).ToString
      If Entry.Attributes.Contains("telephonenumber") Then tmpDataRow.Item("Business Phone") = Entry.Attributes.Item("telephonenumber").Item(0).ToString
      If Entry.Attributes.Contains("homephone") Then tmpDataRow.Item("Home Phone") = Entry.Attributes.Item("homephone").Item(0).ToString
      If Not String.IsNullOrEmpty(Entry.DistinguishedName.Trim) Then tmpDataRow.Item("adsPath") = Entry.DistinguishedName.ToString
      dtADSI.Rows.Add(tmpDataRow)
      dtADSI.AcceptChanges()
      tmpDataRow = Nothing
      RefreshDisplay()
    Catch ex As Exception
      MsgBox("AddEntryToTable: " & NewLine() & ex.Message)
    End Try

  End Sub

  Private Sub RefreshDisplay()

    Try
      If dtADSI.Rows.Count > 0 Then
        If Not dgvADSI.Visible Then
          updateUI(Me, "MaximumSize", New Size(intResultsMaxFrmWt, intResultsMaxFrmHt))
          updateUI(Me, "MinimumSize", New Size(intResultsFrmWt, intResultsFrmHt))
          If dgvADSI.InvokeRequired Then
            dgvADSI.Invoke(New AutoResizeColumnsInvoker(AddressOf dgvADSI.AutoResizeColumns))
          Else
            dgvADSI.AutoResizeColumns()
          End If
          updateUI(dgvAHCS, "Visible", False)
          updateUI(dgvADSI, "Visible", True)
          dgvADSI.Sort(dgvADSI.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
        End If
        If dgvADSI.InvokeRequired Then
          dgvADSI.Invoke(New RefreshInvoker(AddressOf dgvADSI.Refresh))
        Else
          dgvADSI.Refresh()
        End If
      End If
    Catch ex As Exception
      MsgBox("dtADSI.Rows.Count: " & NewLine() & ex.Message)
    End Try

  End Sub

  Private Sub RefreshDisplay()

    Try
      If dtADSI.Rows.Count > 0 Then
        If Not dgvADSI.Visible Then
          updateUI(Me, "MaximumSize", New Size(intResultsMaxFrmWt, intResultsMaxFrmHt))
          updateUI(Me, "MinimumSize", New Size(intResultsFrmWt, intResultsFrmHt))
          If dgvADSI.InvokeRequired Then
            dgvADSI.Invoke(New AutoResizeColumnsInvoker(AddressOf dgvADSI.AutoResizeColumns))
          Else
            dgvADSI.AutoResizeColumns()
          End If
          updateUI(dgvAHCS, "Visible", False)
          updateUI(dgvADSI, "Visible", True)
          dgvADSI.Sort(dgvADSI.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
        End If
        If dgvADSI.InvokeRequired Then
          dgvADSI.Invoke(New RefreshInvoker(AddressOf dgvADSI.Refresh))
        Else
          dgvADSI.Refresh()
        End If
      End If
    Catch ex As Exception
      MsgBox("dtADSI.Rows.Count: " & NewLine() & ex.Message)
    End Try

  End Sub

Open in new window

0
 
LVL 7

Accepted Solution

by:
rogerard earned 0 total points
ID: 34138862
Correction - Replace:
updateUI(Me, "MaximumSize", New Size(intResultsMaxFrmWt, intResultsMaxFrmHt))
          updateUI(Me, "MinimumSize", New Size(intResultsFrmWt, intResultsFrmHt))
          If dgvADSI.InvokeRequired Then
            dgvADSI.Invoke(New AutoResizeColumnsInvoker(AddressOf dgvADSI.AutoResizeColumns))
          Else
            dgvADSI.AutoResizeColumns()
          End If
          updateUI(dgvAHCS, "Visible", False)
          updateUI(dgvADSI, "Visible", True)
          dgvADSI.Sort(dgvADSI.Columns(0), System.ComponentModel.ListSortDirection.Ascending)

Open in new window

With:
 
updateUI(Me, "MaximumSize", New Size(intResultsMaxFrmWt, intResultsMaxFrmHt))
            updateUI(Me, "MinimumSize", New Size(intResultsFrmWt, intResultsFrmHt))
            updateUI(dgvAHCS, "Visible", False)
            updateUI(dgvADSI, "Visible", True)
              If dgvADSI.InvokeRequired Then
                dgvADSI.Invoke(New AutoResizeColumnsInvoker(AddressOf dgvADSI.AutoResizeColumns))
                dgvADSI.Invoke(New SortInvoker(AddressOf dgvADSI.Sort), dgvADSI.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
              Else
                dgvADSI.AutoResizeColumns()
                dgvADSI.Sort(dgvADSI.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
              End If

Open in new window

0
 
LVL 7

Author Closing Comment

by:rogerard
ID: 34995326
Answered my own question.
0

Featured Post

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
Article by: Nadia
Linear search (searching each index in an array one by one) works almost everywhere but it is not optimal in many cases. Let's assume, we have a book which has 42949672960 pages. We also have a table of contents. Now we want to read the content on p…
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question