it-swarm.com.ru

Поддерживать позицию прокрутки дерева

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

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

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

21
Matt Hanson

Я думаю, я понял это:

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

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

17
Matt Hanson

Я не 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();
26
Stefan Koell

Другой способ сохранить положение прокрутки без внешних функций - использовать свойство 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, показанный выше. Для расширенных узлов я использую рекурсивную функцию, чтобы пройти через дочерние узлы и добавить путь расширенных узлов в список. Затем расширяет их на основе их пути после добавления детей.

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

6
Josh Stribling

Я обнаружил, что лучше обернуть 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();
}
2
D Lyonnais

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

this.hierarchyTreeView.BeginUpdate();
SetScrollPos(this.hierarchyTreeView.Handle, SB_VERT, 5, true);
this.hierarchyTreeView.EndUpdate();
1
JM88

Это пересмотр прекрасного ответа от 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
}

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

0
peter70

Это отлично работает. Сохраните 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
karrtojal
myTreeView.Nodes[0].EnsureVisible();
0
Alen