Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > WPF и Silverlight > Treeview - неограниченное количество воложений


Автор: shtuceron 5.7.2013, 14:59
Добрый день.

Никак не могу понять как происходит создание и заполнение иерархической структуры списка TreeView. Знаю, что для этого необходимо использовать элемент HierarchicalDataTemplate. Составил тестовый пример и пытаюсь добиться его работоспособности...

Код

<TreeView Name="treeView" ItemsSource="{Binding}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Path=Nodes}">
                   <TextBlock Text="{Binding Path=Name}" />
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:SubNode}" ItemsSource="{Binding Path=SubNodes}">
                    <TextBlock Text="{Binding Path=Name}" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
</TreeView>


Код

class Node
    {
        public string Name { get; set; }

        public ObservableCollection<SubNode> SubNodes { get; set; }

        public ObservableCollection<Node> Nodes { get; set; }

        public Node(string name, ObservableCollection<SubNode> subNode)
        {
            this.Name = name;
            this.SubNodes = subNode;
        }
    }


Код

class SubNode
    {
        private string name;

        public string Name { get; set; }

        public SubNode(string name)
        {
            this.name = name;
        }
    }


и код инициализации коллекций:

Код

ObservableCollection<SubNode> subNodes = new ObservableCollection<SubNode>();
ObservableCollection<Node> nodes = new ObservableCollection<Node>();

subNodes.Add(new SubNode("SubNode1"));
subNodes.Add(new SubNode("SubNode2"));

nodes.Add(new Node("Node1", subNodes));

nodes.Last().Nodes = new ObservableCollection<Node>();
nodes.Last().Nodes.Add(new Node("Node2", subNodes));

treeView.ItemsSource = nodes;


Результат получается:

+Node1
  +Node2

Мне нужно:

+Node1
  SubNode1
  SubNode2
  +Node2
    SubNode1
    SubNode2

Спасибо.

Автор: dzaraev 5.7.2013, 19:28
Вообще, поведение данных классов подробно расписано в MSDN: http://msdn.microsoft.com/ru-ru/library/system.windows.controls.treeview(v=vs.100).aspx, http://msdn.microsoft.com/ru-ru/library/system.windows.hierarchicaldatatemplate(v=vs.100).aspx
Попробую объяснить "на пальцах":
Свойство HierarchicalDataTemplate.DataType - это тип элемента, который TreeView хочет отобразить, например тип Node.
Свойство HierarchicalDataTemplate.ItemsSource - это множество дочерних элементов отображаемого типа, например свойство Node.SubNodes
Т.е. если мы в данной позиции отображаем элемент типа Node и затем разворачиваем его, то для получения дочерних элементов будет использовано его свойство Node.SubNodes. Далее, если в коллекции Node.SubNodes лежали элементы - тоже типа Node, то к ним применяется тот же самый HierarchicalDataTemplate. 
Т.е. если у вас в дереве все элементы одного типа, то достаточно одного HierarchicalDataTemplate.
Если же в дереве встречается ( в любой коллекции, под-коллекции - не важно) элемент другого типа, скажем ExclusiveNode, то для его отображения нужен другой HierarchicalDataTemplate, такой, у которого DataType будет указывать на ExclusiveNode. И если дочерние элементы типа ExclusiveNode хранятся в его свойстве ExclusiveNode.SubExNodes, то у второго HierarchicalDataTemplate свойство ItemsSource будет уже указывать на свойство SubExNodes.
Если вам не нужно у какого-то типа элемента в дереве брать дочерние элементы, можно добавить простой DataTemplate для такого типа.
Еще, у вас в дочерних элементах в желаемом результате представлены разные типы элементов, таким образом, чтобы засунуть их в одну коллекцию, они должны быть совместимыми с типом элементов коллекции. В вашем случае можно использовать коллекцию элементов типа Object.

Короче, вот решение для вашей задачи (я предположил по вашему посту, что у типа SubNode не должно быть дочерних элементов):
Классы узлов:
Код

    public class Node {
        public string Name { get; set; }
        public ObservableCollection<object> Nodes { get; private set; }
        public Node(string name) {
            Name = name;
            Nodes = new ObservableCollection<object>();
        }
    }

    public class SubNode {
        public string Name { get; set; }
        public SubNode(string name) {
            Name = name;
        }
    }

Код XAML:
Код

    <TreeView x:Name="myTree">
        <TreeView.Resources>
            <HierarchicalDataTemplate 
                DataType="{x:Type local:Node}" 
                ItemsSource="{Binding Nodes}"
                >
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type local:SubNode}">
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>

Инициализация:
Код

            Node node1 = new Node("Node1");
            node1.Nodes.Add(new SubNode("SubNode1"));
            node1.Nodes.Add(new SubNode("SubNode2"));
            
            Node node2 = new Node("Node2");
            node2.Nodes.Add(new SubNode("SubNode3"));
            node2.Nodes.Add(new SubNode("SubNode4"));

            node1.Nodes.Add(node2);
            var rootNodes = new List<object>();
            rootNodes.Add(node1);

            myTree.ItemsSource = rootNodes;

Результат: прикреплённая картинка.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)