3

我有一个属性设置为 true的 winformsTreeView控件。我还通过为属性分配和实例来覆盖默认排序器。SortedIComparerTreeViewNodeSorter

AddRange不幸的是,使用该函数添加几千个节点可能需要 10 秒。如果我设置Sorted为 false,则AddRange函数小于 1/2 秒。(请不要讨论添加这么多节点的有效性)

啊哈,我听到你说.. 我的IComparer对象有问题。不是根据探查器。几乎没有时间花在排序对象上,但该AddRange函数位于慢速函数列表的顶部。

这个问题很容易在测试项目中复制。只需创建一个TreeNodes 列表并使用该函数将其添加到现有的扩展树节点中AddRange。这将在树文本上使用默认排序 - 再次慢得不成比例。

为了演示如果我Sorted在测试 probject 中禁用该属性并在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()调用

4

3 回答 3

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在操作它的项目时使用的绘制过程,我们将通过删除项目然后添加它们来导致,因为它需要重新绘制以添加新的您正在添加的项目(对于每个项目)。

在我们对节点集合进行任何更改之前,我们必须调用Sorted = false; 禁用排序(这只是暂时的 - 由于SuspendLayout,用户不会看到任何更改)。然后只需将项目添加到集合中(因为TreeView暂时没有排序,它应该非常快)。然后我们通过调用Sorted = true再次启用排序;将 Sorted 属性设置为 true 将导致集合进行排序。这样,排序将只执行一次(因此TreeView将只通过项目一次)。

还有一件事,如果您为 ListView (tv.ListViewItemSorter) 定义了自定义排序器,请在添加项目之前将其设置为 null,当然只是暂时的,在 ResumeLayout 调用之前再次重新启用它。

于 2012-11-29T09:48:12.997 回答
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();
}

所以我使用反编译器观察 Sort() 方法,我注意到它已经在内部处理了 BeginUpdate/EndUpdate 功能。

然后我将 TagTree.Sort() 移到 BeginUpdate/EndUpdate 之外,并且它工作正常。

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();

我几乎不明白这里发生了什么。为什么它在过去起作用,然后突然停止了。坦率地说,我没有足够的时间进一步挖掘,无论如何,最重要的是在这里:它再次起作用。

于 2013-09-06T13:37:57.563 回答
0

我对 TreeView 控件做了一个简单的扩展。它非常快。它将内部存储移动到字典中,这会产生巨大的影响。在我的真实示例中,我需要加载 100000 条记录。之前是37分钟,现在是2.2秒!!

您可以在 CodeProject 上找到示例和代码:http: //www.codeproject.com/Articles/679563/Fast-TreeView

于 2013-11-08T07:16:01.343 回答