views:

16

answers:

0

I'm building an application that displays a hierarchy of Node objects. Each node has a collection of Field objects, plus a Children property of type ObservableCollection<Node>.

I've created a user control to display the Node objects. This control is a HeaderedItemsControl whose header lays out all of the Field objects, and whose ItemsSource is the Children property. It's all nicely hierarchical.

The problem is in performance. Each node can have any number of children, and the hierarchy can go any number of levels deep. The test data set I'm working with has about 120 nodes and 2800 fields all told. This takes about 15-20 seconds to render once the underlying view model objects are created. It's clear that this is because it's creating visuals for every one of those field objects, even those (about 90% of them) that don't appear on the screen.

The obvious solution is to employ virtualization. But this:

</HeaderedItemsControl.Header>
  <HeaderedItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel/> 
    </ItemsPanelTemplate>
  </HeaderedItemsControl.ItemsPanel>
</HeaderedItemsControl.Header>

appears to have no effect; it renders just as slowly as it does when I use a StackPanel or a DockPanel. I think this is because the panel can't decide whether or not it should virtualize the first item until it knows how tall it is, and to do that it has to go all the way to leaf nodes. But I don't understand why it has to create a visual for every single leaf node in order to do this.

I'm using this simple control template (and why is it, pray tell, that a HeaderedItemsControl doesn't render anything until you set its control template?):

<Style TargetType="HeaderedItemsControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
                <DockPanel>
                    <ContentPresenter ContentSource="Header" DockPanel.Dock="Top"/>
                    <ItemsPresenter Margin="10,0,0,0"/>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Amusingly, if I use a VirtualizingStackPanel instead of a DockPanel in the control template, it doesn't render at all!

I could conceivably use the approach that Bea Stollnitz suggests, of flattening out the hierarchy and displaying it using a regular ItemsControl and indenting. That makes for a lot of code, though, particularly if I want to make some (or all) nodes in the tree collapsible.

As a practical matter, I doubt that I'll ever have an actual real-world case where I'm rendering a hierarchy of nodes that's this big. But it would be nice to have a strategy for what happens when what I doubt will happen happens. Is there another way?