HypernovaDesktop Components · docs
Binarymission
WPF › Virtualizing Collection View

Virtualizing Collection View

.NET Framework 4.8.NET 6 / 8 / 10v2.0.0WPF

A collection view that hands grouped data to a virtualising panel as one flat list, with each group's header as a row of its own – so that BinaryVirtualizingWrapPanel can show thousands of items in groups and still create only the rows in view.

1public types
14public members
1namespaces

Assembly

AssemblyBinarymission.WPF.Data.DataExtensions.dll
Root namespaceBinarymission.WPF.Data.DataExtensions
Target frameworks.NET Framework 4.8, .NET 6 / 8 / 10

Overview

Use it in place of ListCollectionView (or CollectionViewSource) whenever grouped data is shown in a BinaryVirtualizingWrapPanel with IsDataSourceGrouped set. Sorting, filtering and group descriptions work as on any ListCollectionView.

How it works

An ordinary grouped view hands an items control its groups, and the control builds one group item per group, each with a panel of its own – which a virtualising panel cannot see through. This view reports Groups as null, so the items control treats it as a flat list, and puts the groups into that list itself: Count is the items plus one row per group, GetItemAt answers a CollectionViewGroup for a header row and the item for any other, and IndexOf is its inverse. The real groups are still built underneath, and GroupsCount says how many there are.

Header rows

A header row reaches the items control as an ordinary item whose data is the CollectionViewGroup, with its Name and ItemCount to bind to. Draw it with an implicit DataTemplate for that type. Its container is an ordinary container, too: to style header rows differently, set CheckForVirtualizedGroupHeadersProperty on the containers and trigger on IsCurrentItemAVirtualizedGroupHeaderProperty. Only the top-level groups get header rows; with more than one group description, the inner levels have none.

Changes to the list

Every index the view raises in its change notifications counts the header rows, so the items control's generator stays in step. An addition is raised at its row, preceded by its group's header when the addition created the group. A removal, move or replacement in a grouped view can empty a group or move an item between groups, so it is raised as a reset; ungrouped, those pass through unchanged.

Getting started

Products grouped by category, header rows styled apart and kept out of selection.

using System.ComponentModel;
using System.Windows.Data;
using Binarymission.WPF.Data.DataExtensions;

var view = new VirtualizingCollectionView(products);    // products: ObservableCollection<Product>
view.SortDescriptions.Add(new SortDescription(nameof(Product.Category), ListSortDirection.Ascending));
view.GroupDescriptions.Add(new PropertyGroupDescription(nameof(Product.Category)));
catalogue.ItemsSource = view;
<ListBox x:Name="catalogue"
         xmlns:data="clr-namespace:Binarymission.WPF.Data.DataExtensions;assembly=Binarymission.WPF.Data.DataExtensions"
         xmlns:vwp="clr-namespace:Binarymission.WPF.Controls.Panels;assembly=Binarymission.WPF.Controls.VirtualizingWrapPanel">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type CollectionViewGroup}">
            <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" />
        </DataTemplate>
    </ListBox.Resources>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="data:VirtualizingCollectionView.CheckForVirtualizedGroupHeaders" Value="True" />
            <Style.Triggers>
                <Trigger Property="data:VirtualizingCollectionView.IsCurrentItemAVirtualizedGroupHeader" Value="True">
                    <Setter Property="Focusable" Value="False" />
                    <Setter Property="IsHitTestVisible" Value="False" />
                    <Setter Property="Background" Value="#FFE8EEF7" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <vwp:BinaryVirtualizingWrapPanel ItemDimension="180,120" IsDataSourceGrouped="True" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

API reference

Binarymission.WPF.Data.DataExtensions

class VirtualizingCollectionViewA collection view that hands grouped data to a virtualising panel as one flat list, with each group's header as a row of its own - so that BinaryVirtualizingWrapPanel can show thousands of items in groups and still create only the rows in view.