How to use UI virtualization with redefined ListBo

2020-04-27 00:21发布

问题:

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?

回答1:

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>


回答2:

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>