Как получить все родительские (до корневых) узлы для выбранных в элементе управления TreeView?

Если у меня есть TreeView (myTreeview), как я могу получить список всех родительских узлов (родительских, родителей родителей и т. Д.) Выбранного узла?


person DevUser    schedule 14.11.2011    source источник


Ответы (4)


Я бы порекомендовал вам создать набор ваших собственных помощников по дереву, например, следующий для вашей проблемы:

    public static class TreeHelpers
    {
        public static IEnumerable<TItem> GetAncestors<TItem>(TItem item, Func<TItem, TItem> getParentFunc)
        {
            if (getParentFunc == null)
            {
                throw new ArgumentNullException("getParentFunc");
            }
            if (ReferenceEquals(item, null)) yield break;
            for (TItem curItem = getParentFunc(item); !ReferenceEquals(curItem, null); curItem = getParentFunc(curItem))
            {
                yield return curItem;
            }
        }

        //TODO: Add other methods, for example for 'prefix' children recurence enumeration
    }

И пример использования (в вашем контексте):

        IList<TreeNode> ancestorList = TreeHelpers.GetAncestors(node, x => x.Parent).ToList();

Почему это лучше, чем использовать list ‹>. Add ()? - потому что мы можем использовать ленивые функции LINQ, такие как .FirstOrDefault (x => ...)

P.S. чтобы включить «текущий» элемент в список результатов, используйте TItem curItem = item вместо TItem curItem = getParentFunc(item)

person Alexander Mavrinsky    schedule 14.11.2011

Если вам нужны реальные объекты, используйте TreeNode.Parent рекурсивно, пока не достигнете корня. Что-то типа:

private void GetPathToRoot(TreeNode node, List<TreeNode> path)
{
    if(node == null) return; // previous node was the root.
    else
    {
        path.add(node);
        GetPathToRoot(node.Parent, path);
    }
}
person Tudor    schedule 14.11.2011
comment
Спасибо! это было очень полезно. Рекурсивные методы очень рекурсивны;) - person JotaPardo; 25.04.2019

Ответ Александра Мавринского действительно полезен, но в моем подходе много изменений. Мой код короче и понятнее не только в методе, но и в сайтах вызовов (за счет указания его дженериков).

public static class TreeExtensions
{
    public static IEnumerable<TreeNode> GetAncestors(this TreeNode node)
    {
        if (node == null)
            yield break;
        while ((node = node.Parent) != null)
            yield return node;
    }
}

Например: var firstCheckedAncestor = treeNode.GetAncestors().First(x => x.Checked);

Или, если вам действительно нужен каждый родительский узел: var allAncestors = treeNode.GetAncestors().ToList();


Но если вы планируете иметь более одного класса с использованием одной и той же логики, вот общий метод и несколько расширений для каждого класса (так что вы можете сохранить более простой API для каждого вызывающего):

public static IEnumerable<T> GetAncestors<T>(T item, Func<T, T> getParent)
{
    if (item == null)
        yield break;
    while ((item = getParent(item)) != null)
        yield return item;
}
public static IEnumerable<TreeNode> GetAncestors(this TreeNode node) => GetAncestors(node, x => x.Parent);
public static IEnumerable<Control> GetAncestors(this Control control) => GetAncestors(control, x => x.Parent);
person Mariano Desanze    schedule 11.05.2019

Я думаю, вам нужно взять массив узлов

List<TreeNode> resultNodes = new List<TreeNode>()
private void GetNodesToRoot(TreeNode node)
{
    if(node == null) return; // previous node was the root.
    else
    {
        resultNodes.add(node);
        GetNodesToRoot(node.Parent);
    }
}
person Saurabh Santhosh    schedule 14.11.2011
comment
эй, без обид ... я просто имел ввиду, что тебе не нужен второй параметр - person Saurabh Santhosh; 14.11.2011