在C#中刷新TreeView后展开所选节点

时间:2011-11-29 09:13:35

标签: c# treeview

我有一个包含很多项目的树视图

当我展开项目及其子项时,在我调用刷新方法后,该扩展项目子项将被折叠。

您能告诉我如何存储所选节点,并在刷新后再次调用Expand方法......

我试过了:

 TreeNode selectedNode = new TreeNode();
 TreeNode selectedNode = SelectedTreeNode();  //method which takes selected node from TV
 RestoreFolderTreeWithLastSelectedItem(); //method which initialise treeview object
 //here I want to call Expand() method but it not exists to TreeNode.

对于treeview,我使用了Windows.Controls.treeView命名空间 我是初学者...... 谢谢

我会通过图片向您解​​释

我展开了所有项目: enter image description here

如果我按F5或调用Refresh函数(RestoreFolderTreeWithLastSelectedItem();),那么它们将像以下一样折叠:

enter image description here

而不是第一张图片...

4 个答案:

答案 0 :(得分:9)

我正在使用WinForms TreeView。它在刷新之间保存节点扩展状态:

// Save the path of the expanded tree branches
var savedExpansionState = treeView1.Nodes.GetExpansionState();

treeView1.BeginUpdate();

// TreeView is populated
// ...

// Once it is populated, we need to restore expanded nodes
treeView1.Nodes.SetExpansionState(savedExpansionState);

treeView1.EndUpdate();

以下是实现此目的的代码:

public static class TreeViewExtensions
{
    public static List<string> GetExpansionState(this TreeNodeCollection nodes)
    {
        return nodes.Descendants()
                    .Where(n => n.IsExpanded)
                    .Select(n => n.FullPath)
                    .ToList();
    }

    public static void SetExpansionState(this TreeNodeCollection nodes, List<string> savedExpansionState)
    {
        foreach (var node in nodes.Descendants()
                                  .Where(n => savedExpansionState.Contains(n.FullPath)))
        {
            node.Expand();
        }
    }

    public static IEnumerable<TreeNode> Descendants(this TreeNodeCollection c)
    {
        foreach (var node in c.OfType<TreeNode>())
        {
            yield return node;

            foreach (var child in node.Nodes.Descendants())
            {
                yield return child;
            }
        }
    }
}

答案 1 :(得分:1)

这很简单。

首先,在刷新之前,我们必须存储扩展节点的ID:

//CollectExpandedNodes(tree.Nodes); - call of function

//this recursive function save ids of expanded nodes to expandedNodeIds
//List<int> expandedNodeIds = new List<int>(); - list for storage id
private void CollectExpandedNodes(TreeListNodes nodes)
{
   foreach (TreeListNode node in nodes)
   {
      if (node.Expanded) expandedNodeIds.Add(node.Id);
      if (node.HasChildren) CollectExpandedNodes(node.Nodes);
   }
}

然后,刷新树后,必须展开其ID存储在expandedNodeIds中的节点:

expandedNodeIds.ForEach((id) =>
{
   TreeListNode node = tree.FindNodeByID(id);
   if (node != null) node.Expanded = true;
});

答案 2 :(得分:0)

这是旧帖子,但我想如果有人来这里,这段代码片段会很有用......

使用以下简单代码保存TreeView State:

//you need to have 4 methods for it and call two of them...
//code where treeview needs to save and restore
var expState = GetAllExpandedNodesList(TreeView);
                    TreeView.Nodes.Clear();
                    //do something else...                    
RestoreTreeViewState(TreeView, expState);
//end of treeview save/restore section


        private static void UpdateExpandedList(ref List<string> expNodeList, TreeNode node)
        {
            if (node.IsExpanded) expNodeList.Add(node.FullPath);
            foreach (TreeNode n in node.Nodes)
            {
                if (n.IsExpanded) UpdateExpandedList(ref expNodeList, n);
            }
        } 

        private static List<string> GetAllExpandedNodesList(TreeView tree)
        {
            var expandedNodesList = new List<string>();

            foreach (TreeNode node in tree.Nodes)
            {
                UpdateExpandedList(ref expandedNodesList, node);
            }
            return expandedNodesList;
        }


        private static void ExpandNodes(TreeNode node, string nodeFullPath)
        {
            if (node.FullPath == nodeFullPath) node.Expand();
            foreach (TreeNode n  in node.Nodes)
            {
                if (n.Nodes.Count >0) ExpandNodes(n, nodeFullPath); 
            }
        }

        private static void RestoreTreeViewState(TreeView tree, List<string> expandedState)
        {
            foreach (TreeNode node in tree.Nodes)
            {
                foreach (var state in expandedState)
                {
                    ExpandNodes(node, state);
                }
            }
        }

答案 3 :(得分:0)

同样,这是一个非常老的问题,但这可能会有所帮助。 它建立在以上示例的基础上,还保留了滚动位置和选择,并作为扩展类编写。

这些节点将尽可能在还原时还原-也就是说,如果选定的节点已被删除,则其父节点将被选择/滚动到。

// To use:
// 
//     var expState = tv.GetExpandedNodesState(TreeView);
//     TreeView.Nodes.Clear();
//     ... reload...
//     tv.RestoreTreeViewState(TreeView, expState);
public static class TreeViewExtensions
{
    public static TreeViewState GetExpandedNodesState(this TreeView tree)
    {
        var expandedNodesList = new List<string>();
        foreach (TreeNode node in tree.Nodes)
        {
            UpdateExpandedList(ref expandedNodesList, node);
        }

        return new TreeViewState(expandedNodesList, tree.TopNode, tree.SelectedNode);
    }

    public static void RestoreExpandedNodesState(this TreeView tree, TreeViewState state)
    {
        tree.BeginUpdate();

        foreach (TreeNode node in tree.Nodes)
        {
            foreach (var nodeState in state.ExpandedNodes)
            {
                ExpandNodes(node, nodeState);
            }
        }

        tree.TopNode = findNodeFromPath(tree, state.TopNodePath);
        tree.SelectedNode = findNodeFromPath(tree, state.SelectedNodePath);
        tree.Focus();

        tree.EndUpdate();
    }

    static TreeNode findNodeFromPath(TreeView tree, string path)
    {
        if (string.IsNullOrWhiteSpace(path))
            return null;

        List<string> elements = path.Split(tree.PathSeparator.ToCharArray()).ToList();

        TreeNode curNode = tree.Nodes.findByText(elements[0]);
        if (curNode == null)
            return null;

        foreach (string element in elements.Skip(1))
        {
            if (curNode.Nodes.findByText(element) != null)
                curNode = curNode.Nodes.findByText(element);
            else
                break;
        }

        return curNode;
    }

    static TreeNode findByText(this TreeNodeCollection tnc, string text)
    {
        foreach (TreeNode node in tnc)
            if (node.Text == text)
                return node;
        return null;
    }

    static void UpdateExpandedList(ref List<string> expNodeList, TreeNode node)
    {
        if (node.IsExpanded) expNodeList.Add(node.FullPath);
        foreach (TreeNode n in node.Nodes)
        {
            if (n.IsExpanded)
                UpdateExpandedList(ref expNodeList, n);
        }
    }

    static void ExpandNodes(TreeNode node, string nodeFullPath)
    {
        if (node.FullPath == nodeFullPath) node.Expand();
        foreach (TreeNode n in node.Nodes)
        {
            if (n.Nodes.Count > 0)
                ExpandNodes(n, nodeFullPath);
        }
    }
}

public class TreeViewState
{
    public TreeViewState(List<string> expandedNodes, TreeNode topNode, TreeNode selectedNode)
    {
        this.ExpandedNodes = expandedNodes;
        this.TopNodePath = topNode != null ? topNode.FullPath : null;
        this.SelectedNodePath = selectedNode != null ? selectedNode.FullPath : null;
    }

    public readonly List<string> ExpandedNodes = null;
    public readonly string TopNodePath = "";
    public readonly string SelectedNodePath = "";
}