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

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

Ответы [ 4 ]

7 голосов
/ 14 ноября 2011

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

    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 => ...)

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

3 голосов
/ 14 ноября 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);
    }
}
0 голосов
/ 11 мая 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);
0 голосов
/ 14 ноября 2011

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

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