jschioppo
jschioppo

Reputation: 43

Nested XAML Treeview Structure with mixed object types

So I've been working on a complex treeview structure using WPF binding. None of the scenarios I've found online have been able to solve the issue, but they have come close.

So I have three objects that look something this:

public class A
{
    public string Name {get; set;}
    public List<A> ListOfA {get; set;}
    public List<B> ListOfB {get; set;}
}

public class B
{
    public string Name {get; set;}
    public List<C> ListOfC {get; set;}
    public List<D> ListOfD {get; set;}
}

public class C
{
    public string Name {get; set;} 
    public List<D> {get; set;}
}

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

It should be noted that the ListOfA, ListOfB, ListOfC, and ListOfD can all be empty. I know this seems convoluted, but it makes perfect sense for my application as to why I'd be doing it this way.

Below is an example of what the treeview could look like

A - Name
    | - A - Name
        | - B - Name
            | - D - Name
            | - D - Name
            | - D - Name
        | - A - Name
            | - B - Name
                | - C - Name
                    | - D - Name
                    | - D - Name
        | - A - Name
    | - A - Name
        | - A - Name
        | - A - Name
    | - A - Name

So I figured out how to format a treeview of A and B with something like below in the A class.

public IList Children
    {
        get
        {
            return new CompositeCollection()
            {
                new CollectionContainer() { Collection = ListOfA },
                new CollectionContainer() { Collection = ListOfB }
            };
        }
    }
}

Which I got from this question: WPF Treeview Databinding Hierarchal Data with mixed types

Below is my XAML code, substituting real objects with A/B/C. Note ListOfA is a view model member.

<TreeView ItemsSource = "{Binding Children}">
    <TreeView.Resources>

        <HierarchicalDataTemplate DataType="{x:Type local:A}" 
         ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding}"/>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate DataType="{x:Type local:B}" 
        ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}"/>
      </HierarchicalDataTemplate>

    </TreeView.Resources>
</TreeView>

This works great, but what I can't figure out is how to functionally add D to this tree view. I've been able to do it by adding a tree view item, with a nested tree view to contain the ListOfD inside the HierarchicalDataTemplate for type B, but I know that isn't a good way to do it.

I also tried adding something like:

<DataTemplate DataType={x:Type local:D>
    <TextBlock Text={Binding Name}/>
</DataTemplate>

But this doesn't work, I assume because not every child of that 'Children' object doesn't have any object of type D inside of it. I'm also not sure how to handle the object of type C, but I'm more focused on D right now, and willing to bet I'll know how to handle it once I get D working anyways.

Am I making this harder than it needs to be, or was I on the right track with nesting things within the Hierarchical Data Template?

Upvotes: 3

Views: 479

Answers (1)

Joel Lucsy
Joel Lucsy

Reputation: 8716

C just needs a template that looks like

<HierarchicalDataTemplate DataType="{x:Type local:C}" ItemsSource="{Binding ListOfD}">
    <TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>

so you'd end of up with:

<HierarchicalDataTemplate DataType="{x:Type local:A}" ItemsSource="{Binding Children}">
    <TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:B}" ItemsSource="{Binding Children}">
     <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:C}" ItemsSource="{Binding ListOfD}">
    <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplateDataType="{x:Type local:D}">
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>

and your classes:

public class A
{
    public string Name {get; set;}
    public List<A> ListOfA {get; set;}
    public List<B> ListOfB {get; set;}
    public IList Children
    {
        get
        {
            return new CompositeCollection()
            {
                new CollectionContainer() { Collection = ListOfA },
                new CollectionContainer() { Collection = ListOfB }
            };
        }
    }
}

public class B
{
    public string Name {get; set;}
    public List<C> ListOfC {get; set;}
    public List<D> ListOfD {get; set;}
    public IList Children
    {
        get
        {
            return new CompositeCollection()
            {
                new CollectionContainer() { Collection = ListOfC },
                new CollectionContainer() { Collection = ListOfD }
            };
        }
    }
}

public class C
{
    public string Name {get; set;} 
    public List<D> ListOfD {get; set;}
}

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

Upvotes: 3

Related Questions