2017-02-20 8 views
0

У меня есть некоторые узлы, добавленные в мой TreeView (trvP). Корневой элемент имеет значение Tag, установленное на Root.Попытка установить все проверенные состояния узлов в дереве - получить 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 функции:

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; 
    } 

Кажется, от отладки, что он запускает var nodes = ... часть кода снова и снова, в то время как только установка одного узла внутри foreach петли (корневого узла) , Однако nodes - это правильный список узлов с правильными значениями.

Я не понимаю, почему это происходит снова и снова, в результате чего возникает исключение.

+0

Можете ли вы показать 'GetAllNodes()' 'расширение для TreeNode' (вы только показать один для' TreeView')? –

+0

И я полагаю, что корневой узел будет первым в вашем списке, поэтому 'node.Checked = ...' снова вызовет обработчик 'trvP_AfterCheck()' для того же узла (хотя это не должно происходить, если в checkstate не было изменение). –

+0

Добавлено, но, как сказано ниже, 'GetAllNodes' отлично работает, если я назову его для некоторого случайного дочернего элемента (который также имеет дочерние элементы) - это только корневой элемент, вызывающий проблемы. – Janushoff

ответ

1

Ваш GetAllNodes() расширение для TreeView начинается с первого дочернего узла и вызывает расширение GetAllNodes() для этого TreeNode.

Это расширение GetAllNodes() добавляет это очень TreeNode в список результатов.
Таким образом, сначалаTreeNode в вашем списке - ваш корневой узел снова.

Это означает, что в строке

node.Checked = e.Node.Checked; 

установить Checked свойство вашего корневого узла, который, в свою очередь, вызывает обработчик trvP_AfterCheckснова для этого корневого узла. Это теперь повторяется бесконечно, наводнение вашего стека и повышение 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; 
      } 
     } 
} 

Btw: хорошая вещь о методах расширения является то, что вы можете называть их синтаксически, как если бы они были instanc методы. Так что

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

просто можно записать в виде

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

Я не считал, что полный список будет поднимать событие снова и снова, это отличное объяснение, спасибо. – Janushoff

0

вы вызываете GetAllNodes рекурсивно, что делает петлю в бесконечное состояние ..

попробовать

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; 
} 

, когда вы уже зацикливание TreeNode в _trv.Nodes, вы Jst нужно добавить текущий узел в Еогеасп заявление.

+0

Нет, это пропускает дочерние узлы. Вызов рекурсивно кажется правильным в коде OP, поскольку рекурсия останавливается, когда нет дочерних узлов ниже. –

+0

GetAllNodes отлично работает, когда я использую его с другим «тегом», он работает так, как ожидалось, только при попытке работать с элементом 'Root' он генерирует исключение. – Janushoff

+0

@ RenéVogt согласен, я думал, что ему нужно пройти только через родителей узлов, извините за промах. – user7417866

Смежные вопросы