2

I'm trying to use ListBox as a view containing multiple items and, of course, I need to use UI virtualization in it.

The problem is virtualization works only when I declare ListBox this way:

<ListBox 
    ItemsSource="{Binding ItemsSource}" 
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Recycling">

    <ListBox.ItemTemplate>
        <DataTemplate>
            <views:SiteEntryView />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

But if I try to customize it, it doesn't virtualizing anymore:

<ListBox 
    ItemsSource="{Binding ItemsSource}" 
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Recycling">

    <ListBox.Template>
        <ControlTemplate>
            <ScrollViewer>
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ListBox.Template>

    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <views:SiteEntryView />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

As far as I've found, this sample contains just the same that ListBox contains by default. But virtualization isn't working. I've read several articles and also couple of answers here, but still can't figure out the "general way" - what and where I must set, bind, add, etc to make virtualization work with custom templates?

Adi Lester
  • 24,731
  • 12
  • 95
  • 110
yaapelsinko
  • 639
  • 1
  • 10
  • 18

2 Answers2

4

Two things:

Update your PanelTemplate to use a VirtualizingStackPanel and add your virtualization options to the ScrollViewer of the ControlTemplate.

<ListBox.Template>
    <ControlTemplate>
        <ScrollViewer VirtualizingStackPanel.IsVirtualizing="True"
                      VirtualizingStackPanel.VirtualizationMode="Recycling">
            <ItemsPresenter />
        </ScrollViewer>
    </ControlTemplate>
</ListBox.Template>

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
         <VirtualizingStackPanel />
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>

<ListBox.ItemTemplate>
    <DataTemplate>
        <views:SiteEntryView />
    </DataTemplate>
</ListBox.ItemTemplate>

d.moncada
  • 16,900
  • 5
  • 53
  • 82
  • I see that properties works either on ListBox or ScrollViewer. Does It mean that properties can be set on some root of a visual tree (I mean some element that appears root to its child tree), or is it some WPF's "automagical" stuff? – yaapelsinko Feb 05 '15 at 23:25
  • I've experienced issues in the past (with lots of real-time data) that the properties did not work well when provided on the root ListBox node. I forgot where, but I came across a blog post that stated it should be set within the ControlTemplate itself; and ever since then virutalizaiton has been working better. – d.moncada Feb 05 '15 at 23:36
  • @d.moncada You're right! It seems that List View doesn't have this problem? – CodingNinja Jul 19 '23 at 07:14
2

The reason is that you're using a StackPanel for your ItemsPanel - you should be using a VirtualizingStackPanel instead (which is also the default ItemsPanel for ListBox).

Either remove your ItemsPanel definition or modify it to use a VirtualizingStackPanel:

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <VirtualizingStackPanel />
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>
Adi Lester
  • 24,731
  • 12
  • 95
  • 110