Solved

Datagridview on vb.net form not updating from other thread

Posted on 2010-11-24
14
650 Views
Last Modified: 2012-05-10
I have a datagrid view on a vb.net form that lists new files on a directory.
When opening the form, it checks for existing files, and adds them to the datagridview without any problem.
I have a FileSystemWatcher class that monitors for new files. when its Created event is triggered, it calls the same sub to add the entry to the datagrid view. Unfortunately, this form does not reflect the changes - presumably because the thread is not the same as the main form's.

I know the event is triggered because it runs through all the code, it's just that the Datagrid control is ignoring the call to update it.
I've tried using the InvokeRequired property but it doesn't work with this control type it seems.
 Any idea how to get the control to update when called from the event procedure?
Dim WithEvents varWatchUpload As System.IO.FileSystemWatcher

    Delegate Sub UpdateEDIList_Callback(ByVal pmFileNumber As Integer, ByVal pmDescription As String, ByVal pmFilePath As String)

    Public Sub UpdateEDIList(ByVal pmFileNumber As Integer, _
                         ByVal pmDescription As String, _
                               ByVal pmFilePath As String)

        If Me.EDIList1.InvokeRequired Then
            EDIList1.BeginInvoke(New UpdateEDIList_Callback(AddressOf Me.UpdateEDIList), New Object() {pmFileNumber, pmDescription, pmFilePath})
        End If


        Dim NewRow(4) As Object
        NewRow(0) = Date.Now
        NewRow(1) = pmFileNumber
        NewRow(2) = pmDescription
        NewRow(3) = pmFilePath

        Me.EDIList1.Rows.Add(NewRow)

FinishOff:
        Exit Sub

    End Sub

Open in new window

0
Comment
Question by:Billy_London
[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
  • 6
  • 6
  • 2
14 Comments
 
LVL 32

Expert Comment

by:Erick37
ID: 34205397
Assuming the grid is on the form, then you could use this:

If Me.InvokeRequired Then
            Me.Invoke(New UpdateEDIList_Callback(AddressOf Me.UpdateEDIList), New Object() {pmFileNumber, pmDescription, pmFilePath})
        End If

0
 
LVL 3

Author Comment

by:Billy_London
ID: 34205667
It will work if all the code is run from the main form's module.
however, i call code from other modules that in turn calls the form's UpdateEDIList method.
The files are large xml messages that need a lot of code so I don't want to clog up the main form's code.

Me.InvokedRequired always returns False when another module calls it; the code will run, but the Datagrid is not updated.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 34205866
The code you posted does not reflect that scenario so it's difficult to visualize what the sequence of events is.

Can you post a simplified version of what you are trying to do?  How is the other code instantiated and run?
0
How our DevOps Teams Maximize Uptime

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

 
LVL 3

Author Comment

by:Billy_London
ID: 34205938
The main form has varWatchUpload event procedure that runs when new file is created on target directory:

    Private Sub varWatchUpload_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles varWatchUpload.Created
        CheckIndividualFile(e.FullPath)
    End Sub

Sub CheckIndividualFile is in a separate module. It takes only one parameter - the filepath. It opens the file, reads xml, extracts some data and puts it into our database. Then it calls the Datagrid update procedure on the main form as in: Form1.UpdateEDIList(varFileNumber, varDocType, varFileName) so user can see summary of what file has been processed.
0
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 34205961
When you step through the code, is the code in the update sub not executing at all? How about you using the file system watcher and uploading the XML to the database and the main form uses the SQLDependency to detect the new records and refreshes the grid?

http://www.codeproject.com/KB/database/chatter.aspx
0
 
LVL 32

Expert Comment

by:Erick37
ID: 34206082
I would recommend modifying the function to return the results to the calling procedure.  You could use a datarow, a collection, or user type to return the results in.

Private Sub varWatchUpload_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles varWatchUpload.Created
        Dim results As List(Of String) ''or DataRow
        results = CheckIndividualFile(e.FullPath)
        If Me.InvokeRequired Then
            Dim d As New UpdateEDIList_Callback(AddressOf UpdateEDIList)
            Me.Invoke(d, New Object() {results})
        Else
            ' use async thread
            UpdateEDIList(results)
        End If
        ...

End Sub
0
 
LVL 3

Author Comment

by:Billy_London
ID: 34206427
CodeCruiser:
The project has different routines that check for files from different directories. Some are xml that need to be logged on the db. Some are different kinds that won't be logged in db but need to be redirected to another folder. In that case there's no logging on the db, so no event to latch onto.
SQLDependency is nice idea though.

Erick37: I will go with your method for the moment. I did consider that at some point, but it's not ideal. It means that any subrouting that wants to send log something on the datagrid has to be converted to a function that returns those variables.

If anyone else has an idea how to bypass this thread protection on the form let me know please otherwise i'll close question.

thanks
0
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 34206445
>but need to be redirected to another folder. In that case there's no logging on the db, so no event to latch onto.
Do you need to interact with the grid in that case?
0
 
LVL 32

Expert Comment

by:Erick37
ID: 34206547
It's best practice to encapsulate your data -- meaning do not expose the form's grid to direct update via external processes.  Function calls provide this (and perhaps solve the problem).
0
 
LVL 3

Author Comment

by:Billy_London
ID: 34206562
CodeCruiser:
some EDI files might not be recognised by us, in which case I wouldn't log them on the db, i would put them in a separate folder. but i'd still want to report to the "dashboard" that it's processed the file.
It may also have an error logging onto the db, say because of unique index key violation with duplicate xml file, in which case I want to report to the dashboard that it couldn't process it and why.

That's a business logic question anyhow. This threading protection will crop up again in other areas, so it would be nice to know the solution rather than adapt my code around it.

Erick: the external process doesn't access the grid directly, it uses the public subroutine on the main form. Are you suggesting just changing the sub to a function or can you give me an idea what you mean pls?
0
 
LVL 32

Expert Comment

by:Erick37
ID: 34206643
You are correct.  I see that your external code calls the Forms public sub.

Question:  is CheckIndividualFile a Shared function or is it in a class instantiated by the main form?
0
 
LVL 3

Author Comment

by:Billy_London
ID: 34206667
CheckIndividualFile is a public sub/function in a separate module
do you think it would make a difference if it was a class object?
0
 
LVL 32

Accepted Solution

by:
Erick37 earned 500 total points
ID: 34207071
I tested your code in a new project and it all works fine.

Since you are declaring the FileSystemWatcher at runtime you have to set the SynchronizingObject to the instance of the form in order for it to work:

Me.varWatchUpload.SynchronizingObject = Me
0
 
LVL 3

Author Closing Comment

by:Billy_London
ID: 34207215
setting SynchronizingObject property was the key!
Now it will update the datagrid when called from separate module.
thanks to both of you.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

734 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