21

如何在 .NET 应用程序中保持树视图控件的滚动位置?例如,我有一个树形视图控件,并经历了一个向其添加各种节点的过程,并将它们固定在底部。在此过程中,我可以滚动浏览树视图并查看不同的节点。问题是当过程完成时,树视图滚动到最底部。

看来调用 treenode.Expand() 是让我偏离轨道的原因。当父节点展开时,它会获得焦点。

有没有解决的办法?如果我在进程运行时查看特定节点,我不希望它在进程完成后跳到我身上。

4

9 回答 9

29

我不是 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();
于 2008-12-11T16:13:43.577 回答
18

我想我想通了:

  1. 获取树视图顶部的节点。
  2. 展开父节点。
  3. 使之前位于顶部的节点可见。
If treeNodeParent.IsExpanded = False Then
    Dim currentNode As TreeNode = TreeViewHosts.GetNodeAt(0, 0)
    treeNodeParent.Expand()
    currentNode.EnsureVisible()
End If

这是更好的方法吗?

于 2008-12-02T02:18:16.420 回答
7

无需外部函数即可保留滚动位置的另一种方法是使用树的 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 完全相同。对于扩展节点,我使用递归函数循环遍历子节点并将扩展节点的路径添加到列表中。然后在添加子项后根据它们的路径扩展它们。

当然,如果你有很多同名的兄弟节点,这可能也不起作用:-)

于 2012-05-22T02:41:42.907 回答
3

我发现最好SetTreeViewScrollPosition(point)用一个BeginUpdateEndUpdate...

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();
}
于 2010-02-25T14:54:47.943 回答
1

我也有同样的问题,滚动本身更新了,但是树视图的内容没有滚动。这很容易通过添加BeginUpdate()and EndUpdate()around 来解决SetScrollPos()

this.hierarchyTreeView.BeginUpdate();
SetScrollPos(this.hierarchyTreeView.Handle, SB_VERT, 5, true);
this.hierarchyTreeView.EndUpdate();
于 2011-01-11T10:23:30.773 回答
0
myTreeView.Nodes[0].EnsureVisible();
于 2012-03-08T20:53:52.870 回答
0

它是对 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
}

也许它简化了你的工作;-)

于 2014-08-22T13:06:22.997 回答
0

这工作正常。保存 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();
于 2018-12-26T19:27:44.880 回答
-3

最好的办法是使用 UpdatePanel 并将您的树视图标签嵌套在其中。例如,

<asp:UpdatePanel id="UpdatePanel">
     <ContentTemplate>
         <asp:TreeView id="TreeView">

         </asp:TreeView>
     </ContentTemplate>
</asp:UpdatePanel>

它对我有用,我希望它能解决你的问题。

于 2013-05-06T05:54:57.377 回答