2017-02-20 1 views
0

TreeView(trvP)にいくつかのノードが追加されています。ルート要素はTagプロパティがRootに設定されています。すべてのノードをツリービューでステータスをチェックしようとしました - get StackOverflowException

私はルート要素をチェックすると、他のすべてのノードが同じステータスになるようにしています。ただし、以下のコードを実行するとStackOverflowExceptionになります。

private void trvP_AfterCheck(object sender, TreeViewEventArgs e) 
{ 
     if(e.Node.Tag.Equals("Root")) 
     { 
      var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView); 
      foreach (TreeNode node in nodes) 
       node.Checked = e.Node.Checked; 
     } 
} 

GetAllNodes関数のコード:それだけforeachループ(ルートノード)の内部に単一のノードを設定して、それは、何度もコードのvar nodes = ...一部を実行することをデバッグから思わ

public static List<TreeNode> GetAllNodes(this TreeView _trv) 
{ 
     List<TreeNode> result = new List<TreeNode>(); 
     foreach (TreeNode child in _trv.Nodes) 
     { 
      result.AddRange(child.GetAllNodes()); 
     } 
     return result; 
} 
public static List<TreeNode> GetAllNodes(this TreeNode _trn) 
    { 
     List<TreeNode> result = new List<TreeNode>(); 
     result.Add(_trn); 
     foreach (TreeNode child in _trn.Nodes) 
     { 
      result.AddRange(child.GetAllNodes()); 
     } 
     return result; 
    } 

。しかし、nodesは正しい値を持つノードの適切なリストです。

なぜこれが何度も繰り返し実行されているかわかりませんが、例外が発生します。

+0

のように書くことができますが、 'TreeNode'(あなたが唯一の' TreeView'のための1つを表示する)ための 'GetAllNodes()'拡張子を表示することができますか? –

+0

そして、私はルートノードがあなたのリストの最初になるだろうと思うので、 'node.Checked = ...'は同じノードのために再び 'trvP_AfterCheck()'ハンドラを呼び出します(チェックステートが変化する)。 –

+0

追加されましたが、以下に述べるように、いくつかのランダムな子要素(子もあります)を呼び出すと、 'GetAllNodes'は正常に動作します。 – Janushoff

答えて

1

あなたのGetAllNodes()の拡張子は、最初の子ノードから始まり、TreeNodeの拡張子をGetAllNodes()とします。

このGetAllNodes()の拡張子は、この非常にTreeNodeを結果リストに追加します。
最初にTreeNodeルートノードに再びです。

これは順番に、このルートノードのために再びハンドラtrvP_AfterCheckを呼び出して、あなたのルートノードCheckedプロパティを設定する行に

node.Checked = e.Node.Checked; 

を意味します。これは無限に繰り返され、スタックにあふれてStackOverflowExceptionを上げます。これを解決するため、ルートノードをフィルタリングするには

private void trvP_AfterCheck(object sender, TreeViewEventArgs e) 
{ 
     if(e.Node.Tag.Equals("Root")) 
     { 
      var nodes = e.Node.TreeView.GetAllNodes(); 
      foreach (TreeNode node in nodes) 
      { 
       if (node == e.Node) continue; // don't do it for root again 
       node.Checked = e.Node.Checked; 
      } 
     } 
} 

ところで:拡張メソッドの良いところは、彼らがinstancメソッドであるかのようにあなたが構文的にそれらを呼び出すことができるということです。したがって、この

var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView) 

は単に

var nodes = e.Node.TreeView.GetAllNodes(); 
+0

私は完全なリストが何度も何度もイベントを起こすとは考えていませんでしたが、これは素晴らしい説明です。 – Janushoff

0

あなたは

はすでに_trv.NodesにTREENODEするためにループしているとき、あなたはforeachのに現在のノードを追加する必要がありJST

public static List<TreeNode> GetAllNodes(this TreeView _trv) 
{ 
     List<TreeNode> result = new List<TreeNode>(); 
     foreach (TreeNode child in _trv.Nodes) 
     { 
      result.Add(child); 
     } 
     return result; 
} 

を試してみてください。..無限状態にループを作るどの再帰的GetAllNodesを呼び出しています

+0

いいえ、それは子ノードを見落とします。再帰的に呼び出すことは、以下の子ノードが存在しないときに再帰が停止するので、OPコード内で正しいと思われる。 –

+0

GetAllNodesはうまく動作します。 'Root'要素を処理しようとしたときにのみ例外をスローします。 – Janushoff

+0

@RenéVogtは同意するが、私は彼が欠場して申し訳ありませんノードの両親を通過する必要があると思った。 – user7417866

関連する問題