Billy_London
asked on
Datagridview on vb.net form not updating from other thread
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?
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
ASKER
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.
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.
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?
Can you post a simplified version of what you are trying to do? How is the other code instantiated and run?
ASKER
The main form has varWatchUpload event procedure that runs when new file is created on target directory:
Private Sub varWatchUpload_Created(ByV al sender As Object, ByVal e As System.IO.FileSystemEventA rgs) Handles varWatchUpload.Created
CheckIndividualFile(e.Full Path)
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(varFil eNumber, varDocType, varFileName) so user can see summary of what file has been processed.
Private Sub varWatchUpload_Created(ByV
CheckIndividualFile(e.Full
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(varFil
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
http://www.codeproject.com/KB/database/chatter.aspx
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(ByV al sender As Object, ByVal e As System.IO.FileSystemEventA rgs) Handles varWatchUpload.Created
Dim results As List(Of String) ''or DataRow
results = CheckIndividualFile(e.Full Path)
If Me.InvokeRequired Then
Dim d As New UpdateEDIList_Callback(Add ressOf UpdateEDIList)
Me.Invoke(d, New Object() {results})
Else
' use async thread
UpdateEDIList(results)
End If
...
End Sub
Private Sub varWatchUpload_Created(ByV
Dim results As List(Of String) ''or DataRow
results = CheckIndividualFile(e.Full
If Me.InvokeRequired Then
Dim d As New UpdateEDIList_Callback(Add
Me.Invoke(d, New Object() {results})
Else
' use async thread
UpdateEDIList(results)
End If
...
End Sub
ASKER
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
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
>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?
Do you need to interact with the grid in that case?
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).
ASKER
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?
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?
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?
Question: is CheckIndividualFile a Shared function or is it in a class instantiated by the main form?
ASKER
CheckIndividualFile is a public sub/function in a separate module
do you think it would make a difference if it was a class object?
do you think it would make a difference if it was a class object?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
setting SynchronizingObject property was the key!
Now it will update the datagrid when called from separate module.
thanks to both of you.
Now it will update the datagrid when called from separate module.
thanks to both of you.
If Me.InvokeRequired Then
Me.Invoke(New UpdateEDIList_Callback(Add
End If