Solved

Datagridview on vb.net form not updating from other thread

Posted on 2010-11-24
14
617 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
  • 6
  • 6
  • 2
14 Comments
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 3

Author Comment

by:Billy_London
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 83

Expert Comment

by:CodeCruiser
Comment Utility
>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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

728 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now