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   51  

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 либо групповыми, либо входными объектами, а 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..

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