Как удалить все узлы, кроме проверенных, и их родителей в дереве?

У меня есть TreeView, который содержит любое количество узлов. Пользователи могут проверить любой из узлов в TreeView, и как только они нажмут кнопку, я хочу обрезать все, кроме отмеченных узлов и их родителей. У меня есть все настройки кнопки, и она вызывает метод, который должен обрезать узлы, проблема, с которой я столкнулся, - это логика обрезки. Даже псевдокод был бы полезен. Я знаю, что он должен быть рекурсивным и должен начинаться с самых внешних узлов и продвигаться вверх, но я не могу придумать рекурсию.

Меня не волнует, удаляет ли он TreeView напрямую или создает новый List<TreeNode>, к которому я могу привязаться.

Любая помощь будет принята с благодарностью, спасибо.

Решение. Решение от InBetween устранило мою логическую проблему, но осталась еще одна проблема. Вы должны удалить узлы из их родителя. Так что вы не можете просто пойти и сделать TreeView.Remove(node), вы должны сделать ParentNode.ChildNodes.Remove(node).


person Death259    schedule 31.05.2011    source источник


Ответы (3)


Иногда помогает взглянуть на проблему с другой точки зрения.

Почему бы вам сначала не изменить логику того, как дерево управляет проверкой элементов, если это возможно:

Если пользователь отметит элемент, вы не удалите ни этот элемент, ни его родителей. Поэтому, когда пользователь проверяет элемент, проверяйте каждый элемент вверх по дереву, пока не дойдете до корневого элемента выбранного элемента. Это легко реализовать.

Теперь, когда вы выполняете обрезку, вам просто нужно пройти по дереву (начиная с корневых элементов и перемещаясь вниз по дереву) в поисках непроверенных элементов. Вы можете удалить их и, следовательно, все элементы, висящие на нем, не просматривая, есть ли выбранные элементы в этой ветке.

Возможно, этот вариант недействителен из-за ваших требований.

person InBetween    schedule 31.05.2011
comment
Спасибо! В итоге я использовал вашу логику и сделал так, что всякий раз, когда флажок установлен, его родитель был проверен. Когда я загружаю древовидную структуру, я проверяю всех родителей тех, которые были сохранены в БД, а затем я просто удаляю все, что не проверено. - person Death259; 01.06.2011

Мне пришлось сделать что-то подобное, когда при нажатии на дочерний элемент автоматически выбирался родитель. Итак, я думаю, это может помочь, так как сначала будут выбраны все родители, а затем вы можете очистить, выполнив поиск выбранных (сверху):

    private void RecursiveCheckNodesDown(TreeNodeCollection tree, bool checkedFlag)
    {
        if (tree != null) 
            foreach (TreeNode node in tree)
                RecursiveCheckNodesDown(node.Nodes, node.Checked = checkedFlag);
    }

    private void RecursiveCheckNodesUp(TreeNode node, bool checkedFlag)
    {
        if( node != null )
            RecursiveCheckNodesUp(node.Parent, node.Checked = checkedFlag);
    }

    private void SomeTreeBeginUpdate()
    {
        SomeTree.BeginUpdate();
        SomeTree.AfterCheck -= SomeTree_AfterCheck;
    }

    private void SomeTreeEndUpdate()
    {
        SomeTree.AfterCheck += SomeTree_AfterCheck;
        SomeTree.EndUpdate();
    }

    private void SomeTree_AfterCheck(object sender, TreeViewEventArgs e)
    {
        SomeTreeBeginUpdate();
        RecursiveCheckNodesDown(e.Node.Nodes, e.Node.Checked);
        if( e.Node.Checked )
            RecursiveCheckNodesUp(e.Node.Parent, e.Node.Checked);
        SomeTreeEndUpdate();
    }

    this.SomeTree.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.SomeTree_AfterCheck);
person malkia    schedule 31.05.2011
comment
Спасибо за помощь. Я заметил, что вы используете Windows.Forms, если я не понимаю это правильно, разве я не могу не использовать это с приложением ASP.net? - person Death259; 01.06.2011

это можно сделать, внедрив поиск в глубину...

что-то типа

//pseudocode
bool prune(treenode t)
{
   bool mayNotDeleteThisNode=t.isChecked;
   foreach(treenode c in t.childnodes)
   {
      if(prune(c)) mayNotDeleteThisNode=true;
   }

   if(!mayNotDeleteThisNode)
   {
      delete(t)
   }

   return mayNotDeleteThisNode;
}
person DarkSquirrel42    schedule 31.05.2011
comment
Я не совсем уверен, что вы можете удалить узел во время перечисления коллекции узлов. Не удалить удалить узел из cildNodes и, следовательно, изменить коллекцию? Я думаю, вам нужно сделать это с помощью обычных циклов или просто создать новое дерево с выбранными узлами. - person InBetween; 01.06.2011
comment
поэтому ... псевдокод ... delete также может быть реализован как функция, которая каким-то образом хранит эти ожидающие операции удаления, которые будут выполняться после обхода дерева - person DarkSquirrel42; 01.06.2011