Произошло необработанное исключение типа «System.StackOverflowException» в mscorlib.dll.

У меня есть приведенный ниже подраздел, который проверяет все дочерние узлы узла в древовидном представлении формы Windows, когда узел проверяется. Я получаю сообщение об ошибке, указанное в теме, всякий раз, когда я нажимаю на нее, но это происходит только при настройке проверенного свойства. Если я просто запускаю закомментированную строку MsgBox, она работает нормально, без ошибок.

Private Sub TreeView1_AfterCheck(ByVal sender As System.Object, ByVal e As _
    TreeViewEventArgs) Handles TreeView1.AfterCheck
    For Each s As TreeNode In TreeView1.Nodes
        If s.Checked = True Then
            For i As Integer = 0 To s.Nodes.Count - 1
                MsgBox(s.Nodes(i).Text)
                s.Nodes(i).Checked = True
            Next
        End If
    Next
End Sub

Поскольку это исключение StackOverflow, это кажется лучшим местом, чтобы спросить об этом!


person hermiod    schedule 20.07.2009    source источник


Ответы (4)


В документации для события TreeView.AfterCheck говорится:

Установка свойства TreeNode.Checked из обработчика событий BeforeCheck или AfterCheck приводит к тому, что событие возникает несколько раз, что может привести к непредвиденному поведению. Чтобы событие не вызывалось несколько раз, добавьте в обработчик событий логику, которая выполняет ваш рекурсивный код только в том случае, если свойство Action объекта TreeViewEventArgs не установлено на TreeViewAction.Unknown.

Событие возникает каждый раз, когда вы вызываете s.Nodes(i).Checked.

person Jim Mischel    schedule 20.07.2009
comment
Спасибо за ваш ответ Джим. Я использовал комбинацию ваших ответов и ответов Патрика Макдональда в качестве своего окончательного решения. Код находится в комментарии к сообщению Патрика. - person hermiod; 21.07.2009

Что происходит, так это то, что в событии AfterCheck вы «Проверяете» узел дерева, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, который запускает событие AfterCheck, в котором вы «Проверяете» узел, что вызывает переполнение стека.

Чтобы исправить это, не устанавливайте Checked в обработчике событий AfterCheck.

person Community    schedule 20.07.2009
comment
Забавная и яркая иллюстрация проблемы. Хотя можно было бы использовать какое-то форматирование; о) - person Fredrik Mörk; 20.07.2009
comment
Теперь я чувствую себя немного глупо, потому что не понимал этого раньше. Хотя очень забавная иллюстрация проблемы :) - person hermiod; 21.07.2009
comment
Последний совет не является неправильным; немного неполно, да, но не неправильно. Последний совет определенно решит проблему. - person ; 21.07.2009

Эта строка:

s.Nodes(i).Checked = True

вызывает само событие TreeView1_AfterCheck. Так что это бесконечный цикл.

Вам нужно переписать код более тщательно, чтобы не переназначать Checked = True, если Checked уже истинно, и, возможно, использовать приватное поле, чтобы проверить, выполняется ли уже текущее событие при входе.

person Barry Kelly    schedule 20.07.2009

Вместо того, чтобы перебирать все корневые узлы TreeView, вы можете просто перебирать дочерние узлы проверенного узла, вызвавшего событие:

Private Sub TreeView1_AfterCheck(ByVal sender As System.Object, ByVal e As TreeViewEventArgs) Handles TreeView1.AfterCheck
    If e.Node.Checked Then
        For Each child As TreeNode In e.Node.Nodes
            child.Checked = True
        Next
    End If
End Sub

ИЗМЕНИТЬ:

Вам не нужно проверять e.Action здесь, да и не следует по двум причинам:

  • Поскольку вы перечисляете дочерние элементы проверенного узла, у вас не будет проблем с бесконечной рекурсией, которая была у вас в исходном коде.
  • Если вы выйдете, когда e.Action = unknown, то, если у вас есть 3 уровня в древовидной структуре, будут выбраны только непосредственные дочерние элементы выбранного вами узла, а не все потомки.
person Patrick McDonald    schedule 20.07.2009
comment
Спасибо, Патрик. Ниже приведен код, который я решил использовать: If e.Action ‹› TreeViewAction.Unknown Then Для каждого дочернего элемента As TreeNode In e.Node.Nodes child.Checked = e.Node.Checked Next End If Этот способ автоматически работает, чтобы снять все отметки также дочерние узлы. Теперь, как мне закрыть вопрос на этом сайте? - person hermiod; 21.07.2009
comment
Ничего, нашел. Кто бы мог подумать, что это будет такая очевидная большая жирная галочка на странице! :) - person hermiod; 21.07.2009