如何在 .NET 应用程序中保持树视图控件的滚动位置?例如,我有一个树形视图控件,并经历了一个向其添加各种节点的过程,并将它们固定在底部。在此过程中,我可以滚动浏览树视图并查看不同的节点。问题是当过程完成时,树视图滚动到最底部。
看来调用 treenode.Expand() 是让我偏离轨道的原因。当父节点展开时,它会获得焦点。
有没有解决的办法?如果我在进程运行时查看特定节点,我不希望它在进程完成后跳到我身上。
我不是 VB 人,但在 C# 中我是这样做的:
一些 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;
返回当前滚动位置的点的方法:
private Point GetTreeViewScrollPos(TreeView treeView)
{
return new Point(
GetScrollPos(treeView.Handle, SB_HORZ),
GetScrollPos(treeView.Handle, SB_VERT));
}
设置滚动位置的方法:
private void SetTreeViewScrollPos(TreeView treeView, Point scrollPosition)
{
SetScrollPos(treeView.Handle, SB_HORZ, scrollPosition.X, true);
SetScrollPos(treeView.Handle, SB_VERT, scrollPosition.Y, true);
}
然后,当您更新树时,请执行以下操作:
BeginUpdate();
Point ScrollPos = GetTreeViewScrollPos(treeMain);
// write your update code here
SetTreeViewScrollPos(treeMain, ScrollPos);
EndUpdate();
我想我想通了:
If treeNodeParent.IsExpanded = False Then Dim currentNode As TreeNode = TreeViewHosts.GetNodeAt(0, 0) treeNodeParent.Expand() currentNode.EnsureVisible() End If
这是更好的方法吗?
无需外部函数即可保留滚动位置的另一种方法是使用树的 TopNode 属性...
TopNode 获取或设置树视图控件中的第一个完全可见的树节点。
如果您只想扩展一个节点并让它保留顶部节点:
TreeNode topNode = m_Tree.TopNode;
treenode.Expand();
m_Tree.TopNode = topNode;
否则,如果您正在重建树(例如刷新文件结构),则可以使用以下方法...
在清除树之前,存储到顶部节点的完整路径:
string topNodePath = null;
TreeNode topNode = null;
if (m_Tree.TopNode != null)
{
topNodePath = m_Tree.TopNode.FullPath;
}
m_Tree.Clear();
添加节点后,对照 topNodePath 检查其 FullPath:
nodes.Add(node)
if ((topNodePath != null) && (node.FullPath == topNodePath))
{
topNode = node;
}
添加所有节点后,更新树的 TopNode 属性:
if (topNode != null)
{
m_Tree.TopNode = topNode;
}
我对选定和扩展的节点使用了类似的技术。SelectedNode 的工作方式几乎与上面显示的 TopNode 完全相同。对于扩展节点,我使用递归函数循环遍历子节点并将扩展节点的路径添加到列表中。然后在添加子项后根据它们的路径扩展它们。
当然,如果你有很多同名的兄弟节点,这可能也不起作用:-)
我发现最好SetTreeViewScrollPosition(point)
用一个BeginUpdate
和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();
}
我也有同样的问题,滚动本身更新了,但是树视图的内容没有滚动。这很容易通过添加BeginUpdate()
and EndUpdate()
around 来解决SetScrollPos()
。
this.hierarchyTreeView.BeginUpdate();
SetScrollPos(this.hierarchyTreeView.Handle, SB_VERT, 5, true);
this.hierarchyTreeView.EndUpdate();
myTreeView.Nodes[0].EnsureVisible();
它是对 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
}
也许它简化了你的工作;-)
这工作正常。保存 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();
最好的办法是使用 UpdatePanel 并将您的树视图标签嵌套在其中。例如,
<asp:UpdatePanel id="UpdatePanel">
<ContentTemplate>
<asp:TreeView id="TreeView">
</asp:TreeView>
</ContentTemplate>
</asp:UpdatePanel>
它对我有用,我希望它能解决你的问题。