Solved

DataGridView InvalidOperationException

Posted on 2010-11-12
9
681 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

 
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

[Webinar] Code, Load, and Grow

Managing multiple websites, servers, applications, and security on a daily basis? Join us for a webinar on May 25th to learn how to simplify administration and management of virtual hosts for IT admins, create a secure environment, and deploy code more effectively and frequently.

Question has a verified solution.

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

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

740 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