.net 保持树视图的滚动位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/332788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Maintain scroll position of treeview
提问by Matt Hanson
How can I maintain the scroll position of a treeview control in .NET application? For example, I have a treeview control and go through a process of adding various nodes to it tacking them on to the bottom. During this process, I can scroll through the treeview and view different nodes. The problem is when the process completes, the treeview scrolls to the very bottom.
如何在 .NET 应用程序中保持树视图控件的滚动位置?例如,我有一个树视图控件,并经历了向它添加各种节点并将它们添加到底部的过程。在此过程中,我可以滚动浏览树视图并查看不同的节点。问题是当过程完成时,树视图滚动到最底部。
It appears that calling treenode.Expand() is what is throwing me off track here. When a parent node is expanded, it gets the focus.
似乎调用 treenode.Expand() 是让我偏离轨道的原因。当父节点展开时,它会获得焦点。
Is there a way around this? If I'm looking at a specific node while the process is running, I don't want it to jump around on me when the process is done.
有没有解决的办法?如果我在进程运行时查看特定节点,我不希望它在进程完成时跳到我身上。
采纳答案by Matt Hanson
I think I figured it out:
我想我想通了:
- Get the node at the top of the treeview.
- Expand the parent node.
- Make the node that was previously at the top visible.
- 获取树视图顶部的节点。
- 展开父节点。
- 使之前位于顶部的节点可见。
If treeNodeParent.IsExpanded = False Then Dim currentNode As TreeNode = TreeViewHosts.GetNodeAt(0, 0) treeNodeParent.Expand() currentNode.EnsureVisible() End If
If treeNodeParent.IsExpanded = False Then Dim currentNode As TreeNode = TreeViewHosts.GetNodeAt(0, 0) treeNodeParent.Expand() currentNode.EnsureVisible() End If
Is the a better way to do this?
是更好的方法吗?
回答by Stefan Koell
I'm not a VB guy but in C# I do it this way:
我不是 VB 的人,但在 C# 中我是这样做的:
Some Win32 native functions:
一些 Win32 原生函数:
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;
A method which returns a point for the current scroll position:
一种返回当前滚动位置点的方法:
private Point GetTreeViewScrollPos(TreeView treeView)
{
return new Point(
GetScrollPos((int)treeView.Handle, SB_HORZ),
GetScrollPos((int)treeView.Handle, SB_VERT));
}
A method to set the scroll position:
一种设置滚动位置的方法:
private void SetTreeViewScrollPos(TreeView treeView, Point scrollPosition)
{
SetScrollPos((IntPtr)treeView.Handle, SB_HORZ, scrollPosition.X, true);
SetScrollPos((IntPtr)treeView.Handle, SB_VERT, scrollPosition.Y, true);
}
Then when you update your tree, do the following:
然后,当您更新树时,请执行以下操作:
BeginUpdate();
Point ScrollPos = GetTreeViewScrollPos(treeMain);
// write your update code here
SetTreeViewScrollPos(treeMain, ScrollPos);
EndUpdate();
回答by Josh Stribling
Another way you can preserve the scroll position without external functions is using the TopNode property of the tree...
无需外部函数即可保留滚动位置的另一种方法是使用树的 TopNode 属性...
TopNode gets or sets the first fully-visible tree node in the tree view control.
TopNode 获取或设置树视图控件中第一个完全可见的树节点。
If you just want to expand a node and have it preserve the top node:
如果您只想扩展一个节点并让它保留顶部节点:
TreeNode topNode = m_Tree.TopNode;
treenode.Expand();
m_Tree.TopNode = topNode;
Otherwise, if you are rebuilding a tree (such as refreshing a file structure), you can use the following method...
否则,如果您正在重建树(例如刷新文件结构),则可以使用以下方法...
Before Clearing the tree, store the full path to the top node:
在清除树之前,存储顶部节点的完整路径:
string topNodePath = null;
TreeNode topNode = null;
if (m_Tree.TopNode != null)
{
topNodePath = m_Tree.TopNode.FullPath;
}
m_Tree.Clear();
After adding a nodes, check its FullPath against the topNodePath:
添加节点后,根据 topNodePath 检查其 FullPath:
nodes.Add(node)
if ((topNodePath != null) && (node.FullPath == topNodePath))
{
topNode = node;
}
After adding all nodes, update the tree's TopNode property:
添加所有节点后,更新树的 TopNode 属性:
if (topNode != null)
{
m_Tree.TopNode = topNode;
}
I use a similar technique for selected and expanded nodes. SelectedNode works almost exactly as TopNode shown above. For expanded nodes I use a recursive function to loop through the child nodes and add the path of expanded nodes to a list. Then expands them based on their path after the children have been added.
我对选定和扩展的节点使用了类似的技术。SelectedNode 的工作原理几乎与上面显示的 TopNode 完全一样。对于扩展节点,我使用递归函数遍历子节点并将扩展节点的路径添加到列表中。然后在添加孩子后根据他们的路径扩展它们。
Of course, if you have a lot of sibling nodes with the same name, this might not work as well :-)
当然,如果你有很多同名的同级节点,这可能也行不通:-)
回答by D Lyonnais
I found it's best to wrap the SetTreeViewScrollPosition(point)with a BeginUpdateand EndUpdate...
我发现最好SetTreeViewScrollPosition(point)用 aBeginUpdate和EndUpdate...
private void treeViewXml1_Scroll(object sender, ScrollEventArgs e)
{
Point point = treeViewXml1.GetTreeViewScrollPosition();
treeViewXml2.BeginUpdate();
treeViewXml2.SetTreeViewScrollPosition(point);
treeViewXml2.EndUpdate();
}
private void treeViewXml2_Scroll(object sender, ScrollEventArgs e)
{
Point point = treeViewXml2.GetTreeViewScrollPosition();
treeViewXml1.BeginUpdate();
treeViewXml1.SetTreeViewScrollPosition(point);
treeViewXml1.EndUpdate();
}
回答by JM88
I also had the same problem where the scroll itself updated, but the contents of the treeview didn't get scrolled. This was easily fixed by adding BeginUpdate()and EndUpdate()around SetScrollPos().
我也遇到了同样的问题,滚动本身更新了,但树视图的内容没有滚动。这很容易通过添加BeginUpdate()和EndUpdate()周围来解决SetScrollPos()。
this.hierarchyTreeView.BeginUpdate();
SetScrollPos(this.hierarchyTreeView.Handle, SB_VERT, 5, true);
this.hierarchyTreeView.EndUpdate();
回答by Alen
myTreeView.Nodes[0].EnsureVisible();
回答by peter70
It is a revision of the beautiful response from Stefan Koell, as a TreeViewExtension: (complete solution)
它是 Stefan Koell 的漂亮回复的修订版,作为 TreeViewExtension :(完整解决方案)
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
public static class TreeViewExtension
{
#region Constants
private const int ScrollBarHorizontal = 0x0;
private const int ScrollBarVertical = 0x1;
#endregion
#region Public Methods and Operators
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetScrollPos(int hWnd, int nBar);
public static Point ScrollPosition(this TreeView treeView)
{
return new Point(
GetScrollPos((int)treeView.Handle(), ScrollBarHorizontal),
GetScrollPos((int)treeView.Handle(), ScrollBarVertical));
}
public static void ScrollTo(this TreeView treeView, Point scrollPosition)
{
SetScrollPos(treeView.Handle(), ScrollBarHorizontal, (int)scrollPosition.X, true);
SetScrollPos(treeView.Handle(), ScrollBarVertical, (int)scrollPosition.Y, true);
}
[DllImport("user32.dll")]
public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
#endregion
#region Methods
private static IntPtr Handle(this Visual treeView)
{
var handle = IntPtr.Zero;
var hwndSource = PresentationSource.FromVisual(treeView) as HwndSource;
if (hwndSource != null)
{
handle = hwndSource.Handle;
}
return handle;
}
#endregion
}
Perhaps it simplifies your work ;-)
也许它可以简化您的工作;-)
回答by karrtojal
This works fine. Save the TopNode and restore after:
这工作正常。保存 TopNode 并在以下时间恢复:
this.treeView.BeginUpdate();
TreeNode topNode = this.treeView.TopNode;
// your code
this.treeView.Sort();
this.treeView.SelectedNode = auxNode;
this.treeView.TopNode = topNode;
this.treeView.EndUpdate();
回答by user2353540
The best thing is to use UpdatePanel and nest your treeview tags inside it. For example,
最好的办法是使用 UpdatePanel 并将您的树视图标签嵌套在其中。例如,
<asp:UpdatePanel id="UpdatePanel">
<ContentTemplate>
<asp:TreeView id="TreeView">
</asp:TreeView>
</ContentTemplate>
</asp:UpdatePanel>
It worked for me, and I hope it solves your problem.
它对我有用,我希望它能解决您的问题。

