2012-08-16 24 views
3

我有一個WinForms TreeView控制與Sorted property設置爲true。我還通過將IComparer的實例分配給TreeViewNodeSorter屬性來覆蓋默認分揀機。WinForm的樹狀分類屬性是慢

使用AddRange功能需要也許10秒不幸的是增加了幾千個節點。如果我將Sorted設置爲false,則AddRange函數爲< 1/2秒。 (請不要討論添加這麼多節點的有效性)

啊哈我聽到你說..有我的IComparer對象的問題。不是根據分析器。幾乎沒有任何時間花在排序對象上,但AddRange函數正好位於慢函數列表的頂部。

的問題很容易在測試項目中進行復制。只需創建一個TreeNode s的列表,並使用AddRange函數將其添加到現有的展開樹節點。這將在樹形文本上使用默認排序 - 它又是不成比例的慢。

爲了證明它是多麼的特別慢,如果我禁用測試probject的Sorted性能和使用List<T>.Sort功能(與節點的文本比較委託)將它們添加到樹那裏之前我的節點列表幾乎沒有任何延遲。

這導致排序的節點的替代方法使用AddRange之前手動。沒關係,但是在將節點添加到現有的一組子節點時,這意味着需要進行大量工作才能找到正確的插入點,而不是簡單地將Sorted設置爲true。

無論如何加快行爲?

編輯 - 看來唯一的辦法就是增加前整理..它是有點麻煩,但我想出了下面的擴展方法:

public static void AddSortedRange(this TreeNodeCollection existingNodes, IList<TreeNode> nodes, TreeView treeView, IComparer sorter) 
    { 
     TreeNode[] array = new TreeNode[nodes.Count + existingNodes.Count]; 

     existingNodes.CopyTo(array, 0); 

     nodes.CopyTo(array, existingNodes.Count); 

     Array.Sort(array, sorter); 

     treeView.BeginUpdate(); 

     existingNodes.Clear(); 

     existingNodes.AddRange(array); 

     treeView.EndUpdate(); 
    } 

這是更快現有節點複製到一個數組,追加新的節點,該數組排序,然後替換試圖操縱樹視圖節點在線 - 在上面的代碼中最慢的操作是你都跟事實existingNodes.Clear()呼叫

+0

如何排序_before_加​​入? – 2012-08-16 11:52:29

+1

只有在添加了所有節點後,您才能將Sorted設置爲true嗎? – ken2k 2012-08-16 11:54:58

+0

@UweKeim - 如問題中所述,在現有的一組節點中插入節點是相當多的額外工作 - 特別是將範圍合併到現有集合 – 2012-08-16 12:04:09

回答

1

的性能問題您要將項目添加到排序的TreeView。添加到排序列表後面發生的後果是,對於每個要添加的項目,它會嘗試查找它的位置,這意味着它需要通過整個列表對於每個項目,現在想象有多少迭代,使每一個新項目:)

你可以做的是這樣的:

TreeView tv = new TreeView(); // Just so I have a TreeView variable 
TreeNode[] nodes = ... // Well, your list of nodes that you want to add 
tv.SuspendLayout(); 
tv.Sorted = false; 
tv.Nodes.Clear(); 
tv.Nodes.AddRange(nodes); 
tv.Sorted = true; 
tv.ResumeLayout(); 

對於我們使用的是SuspendLayout/ResumeLayout方法來禁止使用的噴漆工藝性能的原因由TreeView操作它的項目時,我們將通過刪除項目然後添加項目來實現它們,因爲它需要重新繪製以添加要添加的新項目(對於每個項目)。

我們正在做的權利之前向節點的任何更改收藏我們必須調用排序= FALSE;禁用排序(這只是暫時的 - 用戶將不會看到任何更改,因爲SuspendLayout)。 然後只需將項目添加到集合中(因爲TreeView暫時未被排序,所以應該非常快)。 然後我們通過調用Sorted = true;將Sorted屬性設置爲true會導致集合進行排序。 這樣,排序將只執行一次(因此,TreeView只會通過項目)。

還有一件事,如果您爲ListView(tv.ListViewItemSorter)定義了自定義分類器,那麼在添加項目之前將其設置爲null,當然只是暫時的,在ResumeLayout調用之前重新啓用它。

0

我遇到了使用Sort()方法的鎖定情況。

它在幾個星期內運行良好,然後在任務管理器中使用25%的CPU查找應用程序。

var allTags = _TagEngine.GetTags(1, force); 

try 
{ 
    TagTree.BeginUpdate(); 
    TagTree.Nodes.Clear(); 
    foreach (var rec in allTags) 
    { 
     ... adding nodes in the tree 
    } 

    TagTree.Sort(); // <= stuck here ! 
} 
finally 
{ 
    TagTree.EndUpdate(); 
} 

所以我看使用反編譯的排序()方法中,我注意到已經在內部它處理的BeginUpdate/EndUpdate功能。

然後我移動了BeginUpdate/EndUpdate之外的TagTree.Sort(),它工作正常。

var allTags = _TagEngine.GetTags(1, force); 

try 
{ 
    TagTree.BeginUpdate(); 
    TagTree.Nodes.Clear(); 
    foreach (var rec in allTags) 
    { 
     ... adding nodes in the tree 
    } 
} 
finally 
{ 
    TagTree.EndUpdate(); 
} 

TagTree.Sort(); 

我很難理解這裏發生了什麼。爲什麼它在過去工作,並突然停止。坦率地說,我沒有足夠的時間來進一步挖掘,無論如何,最重要的是:它再次運作。

0

我對TreeView控件做了一個簡單的擴展。它非常快。它將內部存儲移動到一個巨大的差異字典。在我的真實世界的例子中,我有100000條記錄需要加載。它花了37分鐘,但現在需要2.2秒!

您可以在CodeProject上找到例子,代碼:http://www.codeproject.com/Articles/679563/Fast-TreeView