WPF TreeView HierarchicalDataTemplate-привязка к объекту с несколькими дочерними коллекциями

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

как я могу использовать HierarchicalDataTemplate так что TreeView будет обрабатывать как подгруппы, так и коллекцию записей?

группы показать подгруппы и записи:

Example:
Group1
--Entry
--Entry
Group2
--Group4
----Group1
------Entry
------Entry
----Entry
----Entry
--Entry
--Entry
Group3
--Entry
--Entry


объекты:


namespace TaskManager.Domain
{
    public class Entry
    {
        public int Key { get; set; }
        public string Name { get; set; }
    }
}

namespace TaskManager.Domain
{
    public class Group
    {
        public int Key { get; set; }
        public string Name { get; set; }

        public IList<Group> SubGroups { get; set; }
        public IList<Entry> Entries { get; set; }
    }
}

4 ответов


A HierarchicalDataTemplate это способ сказать: "вот как вы визуализируете этот тип объекта, и вот свойство, которое можно исследовать, чтобы найти дочерние узлы под этим объектом"

поэтому вам нужно одно свойство, которое возвращает "дочерние" этого узла. например (если вы не можете сделать группу и запись производными от общего типа узла)

public class Group{ ....
        public IList<object> Items
        {
            get
            {
                IList<object> childNodes = new List<object>();
                foreach (var group in this.SubGroups)
                    childNodes.Add(group);
                foreach (var entry in this.Entries)
                    childNodes.Add(entry);

                return childNodes;
            }
        }

Далее вам не нужно HierDataTemplate для записи, так как запись не имеет детей. Поэтому XAML необходимо изменить, чтобы использовать новый Свойство items и DataTemplate для участия:

<TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding Items}">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type local:Entry}" >
            <TextBlock Text="{Binding Path=Name}" />
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

и вот как это выглядит. Screenshot of Output


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

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

таким образом, вы можете выставить свойство в вашей группе объекта

public ObservableCollection<ITreeViewItem> Children { get; set; }

^на этом этапе вы можете принять решение, если это заменяет ваши списки подгрупп и записей, или просто добавляет их вместе и возвращает их в getter собственности...

теперь все, что вам нужно, это заполнить коллекцию Children объектами Group или Entry и HierarchicalDataTemplate будет отображаться правильно, когда объекты помещаются в TreeView..

одна последняя мысль, если запись всегда является "нижним уровнем" дерева (т. е. не имеет детей), то вам не нужно определять HierarchicalDataTemplate для объекта ввода a DataTemplate хватит.

надеюсь, это поможет :)


вот альтернативная реализация ответа Гишу, который возвращает IEnumerable, а не IList, и использует yield ключевое слово для упрощения кода:

public class Group
{
    ...

    public IEnumerable<object> Items
    {
        get
        {
            foreach (var group in this.SubGroups)
                yield return group;
            foreach (var entry in this.Entries)
                yield return entry;
        }
    }
}

этот пост помог мне при поиске решения для той же проблемы:http://blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html

используя MultiBinding и CompositeCollectionConverter..

/С Уважением Андерс