6

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

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

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

4

6 回答 6

6

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

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

            }

        }
于 2013-01-30T13:48:46.020 回答
3

要扩展所有节点,请使用以下代码

treeView1.ExpandAll();

为了扩展选定的节点,请使用以下代码

treeView1.SelectedNode.ExpandAll();

为了扩展特定节点,请使用以下代码

treeView1.Nodes[Index].Expand();
于 2013-01-30T04:59:03.117 回答
2

假设 Nodename 是唯一的。

  • 使用数据库,节点名可以是表的唯一 rowid
  • 树(列表)的状态可以简单地用格式化程序(例如BinaryFormatter) 保存
    • 如果用户想保存状态

只保存展开状态

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

让树视图完成查找要还原的节点的工作

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);
于 2014-09-12T11:25:11.190 回答
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);
   }
}
于 2014-03-06T07:09:44.733 回答
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();
}

希望有帮助

于 2013-01-30T04:34:50.903 回答
1

I know this post is old but if the tree is deep it might not be a good idea to use a recursive traversal of the tree. Since I have not seen any anwser using a non-recursive way here is a solution for doing getting expanded nodes without impacting performance.

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

To use this method, you can do the following:

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

This extension method uses Deep-First traversal in post-order along with the yield keyword to generate an IEnumerable collection.

于 2017-10-27T01:34:16.440 回答