2011-03-18 64 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線程上的添加。

相關問題