我有一个包含很多项目的树视图
当我展开项目及其子项时,在我调用刷新方法后,该扩展项目子项将被折叠。
您能告诉我如何存储所选节点,并在刷新后再次调用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
命名空间
我是初学者......
谢谢
我会通过图片向您解释
我展开了所有项目:
如果我按F5或调用Refresh函数(RestoreFolderTreeWithLastSelectedItem();),那么它们将像以下一样折叠:
而不是第一张图片...
答案 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 = "";
}