user1307149
user1307149

Reputation: 1415

Having trouble binding to a treeview in WPF

I am trying to make a treeview that represents data from a file. The file data has data packets organized into three different sections: Header Info, Operation Header, and Operation Data. The packets in Header Info and Operation Header are one level deep, while the packets in Operation Data are grouped into lists so I thought it'd be easier to organize by making it go an extra level. That way you could pop open Data, see the lists, and pop those open to see individual data packets.

This is my xaml:

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

                    <HierarchicalDataTemplate.ItemTemplate>
                        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                            <TextBlock Text="{Binding Name}" />
                            
                                    <HierarchicalDataTemplate.ItemTemplate>
                                        <HierarchicalDataTemplate>
                                            <TextBlock Text="{Binding DataPackets.ItemName}"/>                                                 
                                        </HierarchicalDataTemplate>
                                    </HierarchicalDataTemplate.ItemTemplate>

                        </HierarchicalDataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>

                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

And here is the code we are trying to bind to the hierarchical datatemplates:

                var childData = new Children();

                result.OperationData.ToList().ForEach(x => childData.DataPackets.Add(x));

                
                if (result.HeaderInfo.Any())
                {
                    TreeViewItems.Add(new TreePair() { TreeNodes = result.HeaderInfoProperties.ToList(), Name = "Header Info" });
                }
                TreeViewItems.Add(new TreePair() { TreeNodes = result.OperationHeaderProperties.ToList(), Name = "Operation Header" });
                TreeViewItems.Add(new TreePair() { TreeNodes = result.OperationDataProperties.ToList(), Children = new List<Children> {childData}, Name = "Operation Data" });

and the classes

public class TreePair
    {
        

        public TreePair()
        {               
            TreeNodes = new List<PropertyInfo>();
            Children = new List<Children>();
        }

        public List<Children> Children { get; set; }

        public List<PropertyInfo> TreeNodes { get; set; }

        public string Name { get; set; }
    }

    public class Children
    {
        public Children()
        {
            DataPackets = new List<DataPacketBase>();
        }

        public string Name { get; set; }

        public List<DataPacketBase> DataPackets { get; set; }
    }

I have the data packets for Header info and operation header showing up, as well as the list names for Operation data but none of the child packets show up. They exist in the Children.DataPackets object.

This is throwing in the output window: BindingExpression path error: 'Children' property not found on 'object'

The second TextBlock is correct, but the Children ItemSource Is not being found, but the list is being filled with items.

enter image description here

Children Name property Missing From Second Level

enter image description here

Upvotes: 0

Views: 840

Answers (1)

nickm
nickm

Reputation: 1775

The binding won't find Children because it is looking for it on a PropertyInfo object. Children and TreeNodes are siblings in the tree, there is no Child/Parent relationship between the two so the HierarchicalDataTemplate is broken when it tries to find the Children object that belongs to PropertyInfo object.

If your object hierarchy is correct then you'll need a CompositeCollection that can combine the TreeNodes and Children objects into a single collection.

    private CompositeCollection _treeNodeChildCollections;
    public CompositeCollection TreeNodeChildCollections
    {
        get
        {
            if (_treeNodeChildCollections == null)
            {
                _treeNodeChildCollections = new CompositeCollection();
                var cc1 = new CollectionContainer();
                cc1.Collection = Children;
                var cc2 = new CollectionContainer();
                cc2.Collection = TreeNodes;

                _treeNodeChildCollections.Add(cc1);
                _treeNodeChildCollections.Add(cc2);
            }

            return _treeNodeChildCollections;
        }
    }

Then bind to that in the xaml.

    <TreeView ItemsSource="{Binding TreeViewItems}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding TreeNodeChildCollections}">
                <TextBlock Text="{Binding Name}" />
                <HierarchicalDataTemplate.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding DataPackets}">
                        <TextBlock Text="{Binding Name}"/>
                        <HierarchicalDataTemplate.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding ItemName}"/>
                            </DataTemplate>
                        </HierarchicalDataTemplate.ItemTemplate>
                    </HierarchicalDataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

Upvotes: 1

Related Questions