2011-03-18 45 views
1

我正在开发一个解析器应用程序,用于从已从数据库中提取的DDL文件构建调用树。这个想法是采取大量的这些DDL文件,并确定究竟是什么调用什么。为此,我正在使用.NET TreeView。我对工作的最终输出是这样的:现在在Visual Basic中锁定另一个线程的控件

-Proc1 
    -Proc2 
    -Proc3 
    -Proc4 
-Proc2 
    -Proc3 
-Proc3 
-Proc4 

,我所有的解析工作正常。虽然这个过程非常漫长。因此,我决定将所有重量级处理都移到自己的线程中。一切都按预期工作,直到我需要更新我的TreeView。我试图保留单独线程上的所有实际更新逻辑,并只更新TreeView。但是,尽管我的主要形式是SyncLocked,但在尝试访问该树时仍遇到异常。

我在网上发现了很多例子,展示了如何使用Delegates进行线程安全访问,但不幸的是,它们都对我的需求有点简单。大多数只是显示如何设置文本属性。正如我前面提到的那样,我试图在工作线程上尽可能多地进行处理,并且只调用相应的TreeView方法来更新,因为此过程可能会很长时间(一次解析和显示数百个过程) 。

是否有一个很好的方法来做到这一点,或者我应该把我的肿块和我的整个依赖树传递回我的主窗体?

这是我目前用来显示第一级依赖关系的代码。请记住,这最终将是递归的(目前在“搞不定”模式),这就是为什么我要保持它关闭UI线程:

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 
+0

你不需要在UI线程上操作树视图吗?您将树视图拉出主窗体,然后将其填充到线程中。我认为你需要将数据传递回UI线程,然后将其填充到那里。 – ChrisWue 2011-03-18 22:43:55

+0

这实际上是我想要避免的。该过程分两步进行。解析DDL文件,然后构建树。由于我正在使用的数据集非常大且具有递归性质,因此我正尝试执行脱机线程树,以便在填充树时UI不会挂起。 – phobos51594 2011-03-18 22:58:58

回答

2

你为什么不使用BackgroundWorker?这比使用Invoke和同步更容易使用。事实上,它旨在缓解这样的事情。

您可以在DoWork事件处理程序中执行您的后台工作,该事件处理程序在其他线程上运行,并安全地与您交互在UI线程中运行的ProgressChanged事件处理程序。使用ReportProgress方法BackgroundWorkerDoWork中发信号通知ProgressChanged

+0

我曾见过BackgroundWorker,但操纵原始线程对我来说似乎更自然。如果我想使用这种方法,我假设我将不得不在UI线程上构建一个函数来抽象插入节点到树中的过程,然后安全地调用它?reportProgress()在我看来有点误导,因为这个过程实际上需要几个步骤,每个步骤修改UI的不同部分。这也是我选择我设计的原因的一部分,因为我希望它能够扩展到处理Treeview。 – phobos51594 2011-03-18 23:07:07

+0

对不起,我不明白。 BackgroundWorker完全按照你的需要 - 它只是为你提供一个“原始”线程来做你的后台工作和一个单独的回调来做你的UI线程的包装。这两者必须是分开的,你不能在工作者线程中混淆UI。它甚至不介意它是否有几个步骤,您可以为每个步骤使用多个工人。在这种情况下自己做是非常容易出错和不必要的。 – 2011-03-19 01:10:50

+0

除了答案,如果你不想使用后台工作,你也可以尝试这些2 尝试的一种方式来看待 http://stackoverflow.com/questions/17266102/visual-basic-child- thread-blocking-main-thread/17281916#17281916 Answer for in multithreading example and http://stackoverflow.com/questions/1142818/new-thread-is-still-blocking-ui-thread?rq=1 回答来自(我)的模型线程....这两个应该给你写代码开始以及。 – Pakk 2013-06-27 13:07:20

0

那么,安全操作UI控件的唯一地方就是UI线程。这在WinForms和WPF中都是如此。您可以将数据传回给UI线程并填充整个树不见你做这样的事情(伪代码):

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

这么做其实就是一个单独的线程应避免超载的UI线程,但它可能需要很长时间才能填充。 AddToTreeView需要调用UI线程上的添加。

相关问题