Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

DataGridView InvalidOperationException

Posted on 2010-11-12
9
Medium Priority
?
727 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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

Question has a verified solution.

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

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
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…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…

636 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