Иерархические данные в TreeView. Найти узел в дереве - PullRequest
0 голосов
/ 20 января 2020

У меня есть TreeView, в котором я отображаю иерархические данные.

Модель

class Node : INotifyPropertyChanged
{
    public string Name { get; set; }
    public ObservableCollection<Node> Nodes { get; set; } = new ObservableCollection<Node>();
}

Хранение узлов:

class NodesStorage : ObservableCollection<Node>
{
    public NodesStorage()
    {
        var node = new Node { Name = "1" };
        node.Nodes.Add(new Node { Name = "1a" });
        node.Nodes.Add(new Node { Name = "1b" });
        node.Nodes.Add(new Node { Name = "1c" });

        var node1 = new Node { Name = "2" };
        node1.Nodes.Add(new Node { Name = "2a" });
        node1.Nodes.Add(new Node { Name = "2b" });
        node1.Nodes.Add(new Node { Name = "2c" });

        this.Add(node);
        this.Add(node1);
    }
}

ViewModel

class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        Nodes = new NodesStorage();
    }

    public ObservableCollection<Node> Nodes;
}

Просмотр

<!--... Set DataContext ...-->

<TreeView ItemsSource="{Binding Path=Nodes}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Nodes}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

<!--...-->

Вопрос

А теперь я хочу создать метод, который возвращает true, если дерево содержит узел с следующим именем и false в другом случае:

public static bool IsTreeContains(Node node, string itemName)
{
    if (node.Name == itemName)
        return true;

    foreach (var n in node.Nodes)
    {
        return IsTreeContains(n, itemName);
    }

    // And what should I write here?
}

Я думаю Я могу использовать возврат здесь. Но это действительно плохая идея.
Как вы думаете?

Ответы [ 2 ]

3 голосов
/ 20 января 2020

Я чувствую, что вы выполняете "своего рода" поиск в глубине в дереве.

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

public static bool IsTreeContains(Node node, string itemName)
{
    // If the current Node matches
    if (node.Name == itemName)
        return true;

    // End of the Tree or the Node Collection
    if (node.Nodes.Count == 0)
        return false;

    foreach (var n in node.Nodes)
    {
        if (IsTreeContains(n, itemName))
            return true;
    }

    return false;
}

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

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Исправлен правильный алгоритм на основе комментариев.

РЕДАКТИРОВАТЬ 1: Исправлено l oop работает только на первого ребенка Узел. Спасибо @ BionicCode.

1 голос
/ 20 января 2020

У вас проблема с вашим рекурсивным методом:

foreach (var n in node.Nodes)
{
    return IsTreeContains(n, itemName);
}

То, что returns означает, что l oop выполняется только один раз.

Вот мой код:

public static bool IsTreeContains(Node node, string itemName)
{
    if (node.Name == itemName)
        return true;

    foreach (var n in node.Nodes)
    {
        if(IsTreeContains(n, itemName))
            return true;          
    }

    return false;
}

Сначала условие выхода, затем, если элемент найден, прекратите итерацию, если нет, продолжайте итерацию. Наконец , если узел и каждый n-дочерний элемент отличаются от искомого элемента, верните false.

Надеюсь, это может вам помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...