Проверка управляющих узлов TreeView и подузлов - StackOverflowException! - PullRequest
0 голосов
/ 19 октября 2010

У меня есть элемент управления Tree View для приложения Windows, в котором используется свойство CheckBoxes.

Иногда (часто), когда узел дерева либо отмечен, либо не отмечен, я получаю исключения переполнения стека в моих статических методах ниже.

Может ли кто-нибудь указать, почему? Может быть, даже покажите мне, как это сделать правильно?

В событии после проверки я написал следующее:

void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) {
  if (0 < e.Node.Nodes.Count) {
    if (e.Node.Checked) {
      e.Node.Expand();
      TreeNodes_SetChecksTo(e.Node, true);
    } else {
      if (!TreeNode_SomethingChecked(e.Node)) {
        e.Node.Collapse(false);
      }
    }
  }
}

Как правило, Исключение выдается, когда что-то в статическом методе запускает событие After Check выше и попадает в один из статических методов ниже:

static void TreeNodes_SetChecksTo(TreeNode node, bool value) {
  if (node != null) {
    if (node.Checked != value) node.Checked = value;
    if (0 < node.Nodes.Count) {
      foreach (TreeNode sub in node.Nodes) {
        TreeNodes_SetChecksTo(sub, value);
      }
    }
  }
}

static bool TreeNode_SomethingChecked(TreeNode node) {
  if (node != null) {
    if (node.Checked) return true;
    if (0 < node.Nodes.Count) {
      foreach (TreeNode sub in node.Nodes) {
        if (TreeNode_SomethingChecked(sub)) {
          return true;
        }
      }
    }
  }
  return false;
}

Ответы [ 3 ]

2 голосов
/ 19 октября 2010

Установка IsChecked внутри TreeNodes_SetChecksTo приводит к возникновению события AfterCheck и, следовательно, к вызову метода TreeNode_AfterCheck.Я подозреваю, что вы хотите отключить / игнорировать событие во время его обработки:

private bool latch;

void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) {
  if (latch)
      return;

  latch = true;

  try
  {
      if (0 < e.Node.Nodes.Count) {
        if (e.Node.Checked) {
          e.Node.Expand();
          TreeNodes_SetChecksTo(e.Node, true);
        } else {
          if (!TreeNode_SomethingChecked(e.Node)) {
            e.Node.Collapse(false);
          }
        }
      }
  }
  finally
  {
      latch = false;
  }
}
2 голосов
/ 19 октября 2010
if (node.Checked != value) node.Checked = value;

Это утверждение, вероятно, вызывает его. Вызывает событие AfterCheck. Ваш обработчик событий будет вызван снова, пока он уже запущен. Вы должны защитить себя от этого и прервать рекурсию с помощью частного поля. Как то так:

private bool updatingChecks;

void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) {
  if (updatingChecks) return;
  updatingChecks = true;
  try {
    // etc..
  }
  finally {
    updatingChecks = false;
  }
}
0 голосов
/ 19 октября 2010

Дерево рекурсивно повторяется каждый раз, когда (под) узел проверяется или не проверяется, и это происходит довольно часто, когда вы реагируете на каждое изменение состояния проверки с помощью обратного вызова AfterCheck. Либо «запретите» обратный вызов, пока его «экземпляр» уже обрабатывает, либо сделайте это без явной рекурсии, и пусть обратный вызов делает рекурсию неявно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...