Binding Multiple Classes to a WPF Treeview

24 Views Asked by At

I have my Treeview binding correctly to the ClassModel but I will have some classmodels that will have child CADModels, I cant get my heirchy template to work correctly

Thanks in advance

Marc

<TreeView.Resources>
    <!-- HierarchicalDataTemplate for ClassModel -->
    <HierarchicalDataTemplate DataType= "{x:Type models:ClassModel}" ItemsSource = "{Binding Path=ChildClasses}">
        <TextBlock Text="{Binding Path=ClassName}"/>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type models:CADModel}">
        <TextBlock Text="{Binding Path=PartNumber}"/>
    </DataTemplate>
</TreeView.Resources>
public interface IClassModel : ITreeNode
{
    ObservableCollection<ClassModel> ChildClasses { get; set; }
    ObservableCollection<CADModel>? CADModels { get; set; }
    int ClassId { get; set; }
    int ParentClassId { get; set; }
    string ClassName { get; set; }
    bool HasChildClass { get; set; }
    LibraryModel? ParentLibrary { get; set; }
}

public class ClassModel : TreeNode, IClassModel
{
    public LibraryModel? ParentLibrary { get; set; } = null;
    public int ParentClassId { get; set; } = 0;
    public int ClassId { get; set; } = 0;
    public string ClassName { get; set; } = string.Empty;
    public bool HasChildClass { get; set; } = false;

    public ObservableCollection<ClassModel> ChildClasses { get; set; } = new ObservableCollection<ClassModel>();
    public ObservableCollection<CADModel>? CADModels { get; set; } = null;

    public ClassModel()
    {
        if (HasChildClass == false)
        {
            CADModels = new ObservableCollection<CADModel>()
            {
                new CADModel()
                {
                    Id = 0,
                    PartNumber = "Bob",
                    Revision = "A.1"
                }
            };
        }
    }
}
public interface ICADModel : ITreeNode
{
    string PartNumber { get; set; }
    string Revision { get; set; }
}
public class CADModel :TreeNode, ICADModel
{
    public string PartNumber { get; set; } = string.Empty;
    public string Revision { get; set; } = string.Empty;
}

enter image description here

I was expecting that i would see one CADmodel leaf called "Bob" below every ClassModel node

1

There are 1 best solutions below

0
Peregrine On

A HierarchicalDataTemplate can only bind to a single collection for its Children.

So, in your ClassModel add a new calculated property

public List<TreeNode> AllChildren => ChildClasses.Cast<TreeNode>().Union(CADModels).ToList();

and change the binding for ItemsSource in your HierarchicalDataTemplate to reference this new AllChildren property instead.

Although the AllChildren list is just a collection of TreeNode items, the TreeView control will check each child item's actual type and use the designated data template for each one.

It doesn't matter if a particular ClassModel can have either child classes or cad models, or both.

If you really are adding child classes or cad models once the tree is already displayed then you will need to handle the CollectionChanged event of your ObservableCollections to refresh this AllChildren property. If not, replace the ObservableCollection<> declared proprties with List<> instead.

Also, unless you have good reason, there is no need to create interfaces for every object type when there is only one implementation of each.