WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections wpf wpf

WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections


A HierarchicalDataTemplate is a way of saying 'this is how you render this type of object and here is a property that can be probed to find the child nodes under this object'

Therefore you need a single property that returns the 'children' of this node. e.g. (If you can't make both Group and Entry derive from a common Node type)

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;            }        }

Next you don't need a HierarchicalDataTemplate for entry since an entry doesn't have children. So the XAML needs to be changed to use the new Items property and a DataTemplate for Entry:

<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>

And here's what that looks like.Screenshot of Output


I think you are most of the way there... with a tiny bit of rework you should get this working fairly easily...

I would suggest you create a base abstract class (or an interface, whichever you prefer) and inherit/implement it for both the Group and Entry class...

That way, you can expose a property within your Group object

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

^at this point, you can make a decision if this replaces your lists of SubGroups and Entries, or merely appends them together and returns them in the property getter...

Now all you need is to populate the Children collection with either Group or Entry objects, and the HierarchicalDataTemplate will render correctly when the objects are placed in the TreeView..

One final thought, if Entry is always the 'bottom level' of the tree (ie has no children) then you do not need to define a HierarchicalDataTemplate for the Entry object, a DataTemplate will suffice.

Hope this helps :)


Here is an alternative implementation of Gishu's answer that returns an IEnumerable rather than an IList, and makes use of the yield keyword to simplify the code:

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;        }    }}