Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winforms Winform treeview排序属性速度较慢_Winforms_Treeview - Fatal编程技术网

Winforms Winform treeview排序属性速度较慢

Winforms Winform treeview排序属性速度较慢,winforms,treeview,Winforms,Treeview,我有一个设置为true的winformsTreeView控件。我还通过将IComparer的和实例分配给TreeViewNodeSorter属性来覆盖默认的分类器 不幸的是,使用AddRange函数添加几千个节点可能需要10秒钟。如果我将Sorted设置为false,则AddRange函数将

我有一个设置为true的winforms
TreeView
控件。我还通过将
IComparer
的和实例分配给
TreeViewNodeSorter
属性来覆盖默认的分类器

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

啊哈,我听到你说。。我的
IComparer
对象中存在问题。根据档案员的说法不是这样的。排序对象几乎没有花费任何时间,而
AddRange
函数正好位于慢函数列表的顶部

这个问题很容易在测试项目中复制。只需创建一个
TreeNode
s列表,并使用
AddRange
函数将其添加到现有的扩展树节点中。这将使用树文本的默认排序-同样,它的速度非常慢

为了演示在将节点添加到树之前,如果在测试probject中禁用
Sorted
属性并在节点列表上使用
List.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();
    }
public static void AddSortedRange(此TreeNodeDeCollection现有节点、IList节点、TreeView TreeView、IComparer分拣机)
{
TreeNode[]数组=新的TreeNode[nodes.Count+existingNodes.Count];
existingNodes.CopyTo(数组,0);
CopyTo(数组,existingNodes.Count);
数组.排序(数组,分类器);
treeView.BeginUpdate();
existingNodes.Clear();
existingNodes.AddRange(数组);
EndUpdate();
}

将现有节点复制到数组、附加新节点、对数组进行排序,然后替换试图在树状视图中内联操作节点的数组会更快—上述代码中最慢的操作是
existingNodes.Clear()
call

您遇到的性能问题与您正在将项目添加到已排序的树视图中有关。当你添加到一个排序列表中时,幕后发生的事情是,对于你正在添加的每个项目,它试图找到它的位置,这意味着它需要遍历整个列表每个项目,现在想象一下每个新项目的迭代次数:)

你能做的是:

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方法来禁用树状视图在操作其项目时使用的绘制过程,这将通过删除项目然后再添加项目来实现,因为需要重新绘制以添加您正在添加的新项目(针对每个项目)

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


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

我使用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();
}

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

我对TreeView控件做了一个简单的扩展。它非常快。它将内部存储移动到一个字典,这将产生巨大的差异。在y现实世界的例子我有100000条记录需要加载。之前需要37分钟,但现在需要2.2秒


您可以在CodeProject上找到示例和代码:

添加前排序如何?难道您不能仅在添加所有节点后将Sorted设置为true吗?@UweKeim-如问题中所述,在现有节点集中插入节点需要做大量额外的工作,尤其是将一个范围合并到现有节点中collection@ken2k-那太棒了将延迟移到Sorted属性..,这与将Sorted保留为false并在Add之后调用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();