首页 文章

如何在树视图中获取所有扩展节点?

提问于
浏览
6

我有一个包含TreeView的程序 . 除根之外的所有节点和根目录下的两个节点都是从数据库加载的 .

当用户将数据添加到数据库时,它必须自动添加到TreeView中 . 我可以通过清除所有节点,添加默认节点并将包括新数据在内的所有数据添加到我的TreeView中来成功完成此操作,但新TreeView的所有节点都已折叠 .

我们的客户希望保留所有扩展节点,但仍然添加他刚刚添加的新数据 . 有没有办法知道所有扩展节点并在折叠或刷新后再次展开?谢谢你的回复 .

6 回答

  • 3

    嗨据我了解,您希望在刷新树视图后保存树视图(通过添加新数据甚至删除一些),您希望展开所有展开的节点,另一个是默认折叠的 . 解决方案是:

    1)在刷新之前保存扩展的树视图节点

    2)刷新树视图数据(注意,如果要删除节点,也要将其从保存的列表中删除)

    3)设置之前保存的树视图

    保存树视图(仅扩展节点) - >此代码查看树视图节点集并保存扩展节点名称在字符串列表中

    List<string> collectExpandedNodes(TreeNodeCollection Nodes)
            {
                List<string> _lst = new List<string>();
                foreach (TreeNode checknode in Nodes)
                {
                    if (checknode.IsExpanded)
                        _lst.Add(checknode.Name);
                    if (checknode.Nodes.Count > 0)
                        _lst.AddRange(collectExpandedNodes(checknode.Nodes));
                }
                return _lst;
            }
    

    现在您已经在列表中收集了扩展节点名称,并且您希望获得树视图外观,您需要2个函数,一个函数通过名称和扩展所选节点的函数检索节点,它的父节点如下:

    如果树节点集合中存在节点,则此函数将检索指向所选节点名称的指针

    TreeNode FindNodeByName(TreeNodeCollection NodesCollection , string Name)
            {
              TreeNode returnNode = null; // Default value to return
              foreach (TreeNode checkNode in NodesCollection)
                {
                    if (checkNode.Name == Name)  //checks if this node name is correct
                        returnNode = checkNode;
                    else if (checkNode.Nodes.Count > 0 ) //node has child
                    {
                        returnNode = FindNodeByName(checkNode.Nodes , Name);
                    }
    
                  if (returnNode != null) //check if founded do not continue and break
                  {
                      return returnNode;
                  }
    
                }
                //not found
                return returnNode;
            }
    

    和此函数展开节点及其父节点

    void expandNodePath(TreeNode node)
            {
                if (node == null)
                    return;
                if (node.Level != 0) //check if it is not root
                {
                    node.Expand();
                    expandNodePath(node.Parent);
                }
                else
                {
                    node.Expand(); // this is root 
                }
    
            }
    

    以下显示了这些功能的用法

    private void button4_Click(object sender, EventArgs e)
            {
                //saving expanded nodes
                List<string> ExpandedNodes = new List<string>();
                ExpandedNodes = collectExpandedNodes(treeView1.Nodes);
                //resetting tree view nodes status to colapsed
                treeView1.CollapseAll();
    
                //Restore it back
                if (ExpandedNodes.Count > 0)
                {
                    TreeNode IamExpandedNode;
                    for (int i = 0; i < ExpandedNodes.Count;i++ )
                    {
                        IamExpandedNode = FindNodeByName(treeView1.Nodes, ExpandedNodes[i]);
                        expandNodePath(IamExpandedNode);
                    }
    
                }
    
            }
    
  • 5

    对于扩展所有节点使用下面的代码

    treeView1.ExpandAll();
    

    用于扩展所选节点使用下面的代码

    treeView1.SelectedNode.ExpandAll();
    

    用于扩展代码下方的特定节点使用

    treeView1.Nodes[Index].Expand();
    
  • 1

    假设Nodename是独一无二的 .

    • 使用数据库,节点名可以是表的唯一rowid

    • 树的状态(List)可以使用Formatter保存(例如BinaryFormatter

    • 如果用户想要保存状态

    仅保存extendedstate

    private List<string> SaveTreeState(TreeNodeCollection nodes)
    {
      List<string> nodeStates = new List<string>();
      foreach (TreeNode node in nodes)
      {
        if (node.IsExpanded) nodeStates.Add(node.Name);
        nodeStates.AddRange(SaveTreeState(node.Nodes));
      }
      return (nodeStates);
    }
    

    让treeview完成查找恢复节点的工作

    private void RestoreTreeState(TreeView tree, List<string> treeState)
    {
      foreach (string NodeName in treeState)
      {
        TreeNode[] NodeList = treeView1.Nodes.Find(NodeName, true);
        if (NodeList.Length > 0) // only if node after reload is avail
          NodeList[0].Expand(); 
      }
    }
    

    使用:

    List<string> StateList = SaveTreeState(treeView1.Nodes);
    ... // reload
    RestoreTreeState(treeView1, StateList);
    
  • 1

    要简单地展开节点,您可以尝试以下代码

    private void button1_Click(object sender, EventArgs e)
    {
      treeView1.Nodes.Add(new TreeNode("New Node",
        new TreeNode[2] { new TreeNode("Node1"), new TreeNode("Node2") }));
      treeView1.Nodes[1].Expand();
    }
    

    希望有所帮助

  • 1

    这很简单 . 下面,您可以看到我的递归版本:

    //List of storage ids of expanded nodes
    List<int> expandedNodeIds = new List<int>();
    //call recursive fun for our tree
    CollectExpandedNodes(tree.Nodes);
    //recursive fun for collect expanded node ids
    private void CollectExpandedNodes(TreeListNodes nodes)
    {
       foreach (TreeListNode node in nodes)
       {
          if (node.Expanded) expandedNodeIds.Add(node.Id);
          if (node.HasChildren) CollectExpandedNodes(node.Nodes);
       }
    }
    
  • 2

    我知道这篇文章很老但是如果树很深,那么使用树的递归遍历可能不是一个好主意 . 由于我没有看到任何使用非递归方式的anwser,因此这是一种在不影响性能的情况下获取扩展节点的解决方案 .

    public static IEnumerable<TreeNodeAdv> CollectExpandedNodes(this TreeNodeAdv root)
    {
        Stack<TreeNodeAdv> s = new Stack<TreeNodeAdv>();
        s.Push(root);
        while (s.Count > 0)
        {
            TreeNodeAdv n = s.Pop();
    
            if (n.IsExpanded)
                yield return n;
    
            foreach (var child in n.Children.ToArray().Reverse())
            {
                s.Push(child);
            }
        }
    }
    

    要使用此方法,您可以执行以下操作:

    foreach (TreeNodeAdv expandedNode in yourTreeView.Root.CollectExpandedNodes())
    {
        //Do processing on the expanded node or add in list.
    }
    

    extension method使用post-order中的Deep-First traversalyield keyword来生成IEnumerable collection .

相关问题