I am developing a parser application to build a call tree from DDL files that have been extracted from a database. The idea is to take a large number of these DDL files and determine exactly what calls what. To do this I am using a .NET TreeView. The final output I am working toward is something like this:
-Proc1
-Proc2
-Proc3
-Proc4
-Proc2
-Proc3
-Proc3
-Proc4
Now, all of my parsing is working correctly. Though, this process is quite lengthy. As such I have decided to move all of the heavyweight processing onto its own thread. Everything is working as intended until I get to the point where I need to update my TreeView. I am attempting to keep all of the actual update logic on the separate thread and only update the TreeView. However, despite having my main form SyncLocked, I am still getting an exception when I try to access the tree.
I have found quite a few examples online that show how to use Delegates for thread-safe access but, unfortunately, they are all a bit simplistic for my needs. Most simply show how to set a text property. As I mentioned before, I am trying to keep as much of the processing as possible on the worker thread and only call the respective TreeView methods to update as this process can be quite long winded (hundreds of procedures to parse and display at a time).
Is there a good way to do this or should I just take my lumps and pass my entire dependency tree back to my main form?
Here is the code I am currently using to display the first level of dependencies. Remember, this will eventually be recursive (currently in “get it working” mode) which is why I want to keep it off the UI thread:
Public Sub updateTreeView()
Dim arrNodeList As ArrayList
Dim childNode As clsProcedureNode
Dim currentNode As clsProcedureNode
Dim intChildIndex As Integer
Dim intNodeListIndex As Integer
Dim treeView As TreeView
//Lock main form
SyncLock mMainForm
//Check that we are actually running on a seprate thread
If mMainForm.InvokeRequired() = True Then
//Call delegate to get handle to TreeView
treeView = mMainForm.Invoke(mGetTreeViewDelegate)
//Add Parsed array to main form TreeView
For intNodeListIndex = 0 To mProcedureNodes.Length - 1
//Get current node and its child list
currentNode = mProcedureNodes(intNodeListIndex)
arrNodeList = currentNode.getProcsCalled()
//Add node and all children to TreeView
With treeView
.BeginUpdate()
.Nodes.Add(currentNode.getName())
For intChildIndex = 0 To arrNodeList.Count
childNode = arrNodeList.Item(intChildIndex)
.Nodes(intNodeListIndex).Nodes.Add(childNode.getName())
Next
.EndUpdate()
End With
Next
End If
End SyncLock
End Sub
Why don’t you use BackgroundWorker? It’s way easier to use than Invoke and synchronization. In fact, it was designed to ease things like this.
You can do your background work in
DoWorkevent handler which runs on other thread and safely interact with you UI inProgressChangedevent handler which runs on UI thread. The need for invokingProgressChangedis signaled inDoWorkusingReportProgressmethod ofBackgroundWorker.