3

プロパティをtrueに設定したwinformsTreeViewコントロールがあります。また、プロパティにインスタンスを割り当てて、デフォルトのソーターをオーバーライドします。SortedIComparerTreeViewNodeSorter

残念ながら、この関数を使用して数千のノードを追加するには、AddRangeおそらく10秒かかります。Sortedfalseに設定すると、AddRange関数は1/2秒未満になります。(非常に多くのノードを追加することの有効性については議論しないでください)

ああ、あなたが言うのを聞きます..私のIComparerオブジェクトに問題があります。プロファイラーによるとではありません。ソートオブジェクトに費やされる時間はほとんどありませんが、そのAddRange関数は低速関数のリストの一番上にあります。

この問題は、テストプロジェクトで簡単に再現できます。のリストを作成し、関数TreeNodeを使用して既存の拡張ツリーノードに追加するだけです。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によって使用されるペイント プロセスを無効にしています。新しいアイテムを追加するには再ペイントする必要があるため、アイテムを削除してから追加することで発生します。追加するアイテム (アイテムごと)。

Nodes コレクションに変更を加える直前に、Sorted = false;を呼び出す必要があります。並べ替えを無効にします (これは一時的なものです。ユーザーはSuspendLayoutのために変更を確認できません)。次に、アイテムをコレクションに追加するだけです ( TreeViewは当分の間ソートされていないため、非常に迅速なはずです)。次に、 Sorted = trueを呼び出して、並べ替えを再度有効にします。Sorted プロパティを true に設定すると、コレクションがソートされます。この方法では、並べ替えは 1 回だけ実行されます (したがって、TreeViewは項目を 1 回だけ処理します)。

もう 1 つ、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 に答える