Поддерживать позицию прокрутки дерева - PullRequest
21 голосов
/ 02 декабря 2008

Как сохранить положение прокрутки элемента управления в виде дерева в приложении .NET? Например, у меня есть древовидный элемент управления, и я прохожу через него процесс добавления различных узлов, прикрепляя их к нижней части. Во время этого процесса я могу просматривать дерево и просматривать разные узлы. Проблема в том, что когда процесс завершается, древовидная структура прокручивается до самого дна.

Похоже, что вызов treenode.Expand () сбивает меня с толку. Когда родительский узел раскрывается, он получает фокус.

Есть ли способ обойти это? Если я смотрю на конкретный узел во время выполнения процесса, я не хочу, чтобы он прыгал вокруг меня, когда процесс завершится.

Ответы [ 9 ]

26 голосов
/ 11 декабря 2008

Я не 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((int)treeView.Handle, SB_HORZ), 
        GetScrollPos((int)treeView.Handle, SB_VERT));
}

Способ установки положения прокрутки:

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); 
}

Затем, когда вы обновите свое дерево, сделайте следующее:

BeginUpdate();
Point ScrollPos = GetTreeViewScrollPos(treeMain);
// write your update code here
SetTreeViewScrollPos(treeMain, ScrollPos);
EndUpdate();
17 голосов
/ 02 декабря 2008

Кажется, я понял это:

  1. Получить узел в верхней части дерева.
  2. Развернуть родительский узел.
  3. Сделать узел, который был ранее вверху, видимым.
If treeNodeParent.IsExpanded = False Then
    Dim currentNode As TreeNode = TreeViewHosts.GetNodeAt(0, 0)
    treeNodeParent.Expand()
    currentNode.EnsureVisible()
End If

Есть ли лучший способ сделать это?

7 голосов
/ 22 мая 2012

Другой способ сохранить положение прокрутки без внешних функций - использовать свойство 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();

После добавления узла проверьте его FullPath по сравнению с topNodePath:

nodes.Add(node)
if ((topNodePath != null) && (node.FullPath == topNodePath))
{
    topNode = node;
}

После добавления всех узлов обновите свойство дерева TopNode:

if (topNode != null)
{
    m_Tree.TopNode = topNode;
}

Я использую подобную технику для выбранных и расширенных узлов. SelectedNode работает почти так же, как TopNode, показанный выше. Для расширенных узлов я использую рекурсивную функцию, чтобы пройти через дочерние узлы и добавить путь расширенных узлов в список. Затем расширяет их в зависимости от их пути после добавления детей.

Конечно, если у вас много узлов с одинаковыми именами, это может не сработать: -)

2 голосов
/ 25 февраля 2010

Я обнаружил, что лучше обернуть 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();
}
1 голос
/ 11 января 2011

У меня также была та же проблема, когда обновлялась сама прокрутка, но содержимое древовидной структуры не прокручивалось. Это легко исправить, добавив BeginUpdate() и EndUpdate() вокруг SetScrollPos().

this.hierarchyTreeView.BeginUpdate();
SetScrollPos(this.hierarchyTreeView.Handle, SB_VERT, 5, true);
this.hierarchyTreeView.EndUpdate();
0 голосов
/ 26 декабря 2018

Это отлично работает. Сохраните 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();
0 голосов
/ 22 августа 2014

Это пересмотр прекрасного ответа от Стефана Коелла в виде 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
}

Возможно, это упростит вашу работу; -)

0 голосов
/ 06 мая 2013

Лучше всего использовать UpdatePanel и вкладывать в него свои древовидные теги. Например,

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

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

Это сработало для меня, и я надеюсь, что это решит вашу проблему.

0 голосов
/ 09 марта 2012
myTreeView.Nodes[0].EnsureVisible();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...