Matt Thomas
Matt Thomas

Reputation: 5744

WPF Wrap items within `TreeView`

Inside a Page I have the below TreeView. How can I get the things inside the ItemsControl to wrap instead of scrolling off the edge of the page? The WrapPanel doesn't seem to be doing anything.

Note this is not the same as asking how to wrap leaf items--I don't need to wrap ItemsControls (there's only one), but need to wrap the things inside the ItemsControl.

<TreeView
    VirtualizingPanel.IsVirtualizing="True"
    VirtualizingPanel.VirtualizationMode="Recycling"
    VirtualizingPanel.ScrollUnit="Pixel"
    VirtualizingPanel.IsVirtualizingWhenGrouping="True"
    Name="Tree">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate
            DataType="{x:Type viewModel:HighLevelItem}"
            ItemsSource="{Binding MidLevelItems}">
            <TextBlock
                Text="{Binding HighLevelName}"/>
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate
                    DataType="{x:Type viewModel:MidLevelItem}">
                    <Expander>
                        <Expander.Header>
                            <TextBlock
                                Text="{Binding MidLevelName}"/>
                        </Expander.Header>
                        <Expander.Content>
                            <ItemsControl
                                ItemsSource="{Binding LowLevelItems}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <WrapPanel
                                            Orientation="Horizontal"/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock
                                            Text="{Binding LowLevelName}"/>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </Expander.Content>
                    </Expander>
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

...here are some type definitions:

public class HighLevelItem
{
    public MidLevelItem[] MidLevelItems { get; set; }
    public string HighLevelName { get; set; }
}
public class MidLevelItem
{
    public LowLevelItem[] LowLevelItems { get; set; }
    public string MidLevelName { get; set; }
}
public class LowLevelItem
{
    public string LowLevelName { get; set; }
}

...and somewhere else in your code (to get the TreeView to populate):

Tree.Items = new[] { new HighLevelItem { HighLevelName = "ALPHA", MidLevelItems = Enumerable.Repeat(0, 1000).Select(_ => new MidLevelItem { MidLevelName = Guid.NewGuid().ToString(), LowLevelItems = Enumerable.Repeat(0, 1000).Select(__ => new LowLevelItem { LowLevelName = "ff" }).ToArray() }).ToArray() } };

Also note that I'm using an Expander instead of continuing with another hierarchical data template because I need that layer to have items arranged horizontally, and changing the Orientation of the VirtualizingStackPanel at any layer within the tree to be different than the other layers breaks UI virtualization for the entire tree when that layer is expanded. Hence all the VirtualizingStackPanels in the above tree have a vertical/default orientation, and horizontal arrangement for the last layer comes from Expanders.

Here's what the above looks like. "ALPHA" is a TopLevelItem, the Guids are MidLevelItems, and each hex pair is an individual LowLevelItem (which you'll notice are not wrapping but continue past the edge):

Screenshot of the above code

Upvotes: 3

Views: 489

Answers (1)

mm8
mm8

Reputation: 169200

You need to specify the Width of the Expander, e.g.:

<Expander Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=TreeView}}">
...

You may want to use a converter or something that subtracts the offset from the left edge side from the ActualWidth of the TreeView.

Upvotes: 1

Related Questions