开发者

Locking a Control from Another Thread in Visual Basic

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.getNam开发者_如何学JAVAe())
                    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 DoWork event handler which runs on other thread and safely interact with you UI in ProgressChanged event handler which runs on UI thread. The need for invoking ProgressChanged is signaled in DoWork using ReportProgress method of BackgroundWorker.


Well, the only place to safely manipulate UI controls is the UI thread. This is so in WinForms and also in WPF. You can either pass back the data to the UI thread and populate the whole tree there or you do something like this (pseudo code):

Sub updateView()
   foreach item in data
      mainForm.AddToTreeView(item);
      Thread.Sleep(1);

Doing that on a separate thread should avoid overloading the UI thread but it might take a long time to populate. AddToTreeView needs to invoke the add on the UI thread.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜