I know this is an old question, but was still relevant for me.
In my case I thought a TreeView
wouldn't cut it because I need exactly two layers, and the types of items displayed are different between the two layers. Also, I'm refactoring a list of Expander
s so I was thinking more one-dimensionally.
But then I realized that you can customize the ItemTemplate
of the TreeView
to include your own HierarchicalDataTemplate
, and that you can customize the ItemTemplate
of that HierarchicalDataTemplate
with your own tailored DataTemplate
... Presto! Exactly two layers with different things in each!
So my point is that the TreeView
is flexible enough that you should try not to create your own custom control.
Here's what I did:
XAML:
<Page x:Class="Foo.Views.TreePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Foo.Views"
xmlns:viewModel="clr-namespace:Foo.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Tree page"
d:DataContext="{d:DesignInstance Type=viewModel:TreeModel}">
<TreeView
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True"
VirtualizingPanel.ScrollUnit="Pixel"
ItemsSource="{Binding Values}"><!-- IList<Person> -->
<TreeView.ItemTemplate><!-- Template for first layer, which has a HierarchicalDataTemplate so that this layer will expand -->
<HierarchicalDataTemplate
ItemsSource="{Binding Expenses}"><!-- IList<Expense> -->
<HierarchicalDataTemplate.ItemTemplate><!-- Template for the second layer, which has a DataTemplate instead of HierarchicalDataTemplate so that this layer won't expand -->
<DataTemplate>
<TextBlock Text="{Binding Amount}"/><!-- Expense amount in dollars -->
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Name}"/><!-- Person name -->
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Page>
The Person
class:
public class Person
{
public string Name { get; set; }
public List<Expense> Expenses { get; set; }
}
The Expense
class:
public class Expense
{
public double Amount { get; set; }
}
Here's how it looks:

I inspected it with Snoop to prove that it is UI Virtualizing. Here's the number of loaded TreeViewItem
s when the app is small:

...And here's the number of loaded TreeViewItem
s when the app is fullscreen (it keeps going beyond this snippet, but you get the idea):

Now it's just the simple matter of styling things to make the nested layer look how I want!
Edit: I just verified that the TreeView
virtualizes all its layers, not just the first layer.