VirtualizingCollectionView
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.
public sealed class VirtualizingCollectionView : ListCollectionView
Inherits from / implements: ListCollectionView
Remarks
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.
Examples
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>See also
Members at a glance
| Constructors | |
|---|---|
VirtualizingCollectionView | Creates a view over a list. Add sort and group descriptions to it afterwards, as to any
ListCollectionView. |
| Properties | |
Count | Gets the number of rows in the view: the items, plus one header row for each top-level group when the view is grouped. |
Groups | Gets null, always, so that an items control lays the view out as one flat list –
with the headers among the rows – instead of generating a group item per group. |
GroupsCount | Gets the number of top-level groups – the number of header rows among the view's rows. |
| Methods | |
GetCheckForVirtualizedGroupHeaders | Gets whether an element is having its header-row flag kept up to date. |
GetIsCurrentItemAVirtualizedGroupHeader | Gets whether an item container currently holds a group's header row. |
GetItemAt | Gets the row at a position in the view: a group's header or an item. |
IndexOf | Gets the row at which an item, or a group's header, appears – the inverse of
GetItemAt. |
OnCollectionChanged | Raises the view's change notification with its positions counted in rows, header rows included, as the items control reads them. |
SetCheckForVirtualizedGroupHeaders | Sets whether an element has its header-row flag,
IsCurrentItemAVirtualizedGroupHeaderProperty, kept up to date. |
SetIsCurrentItemAVirtualizedGroupHeader | Sets the header-row flag on an element. The view sets it itself on checked containers; there is normally no reason to call this. |
SetIsCurrentItemAVirtualizedGroupHeaderProperty | Sets the header-row flag on an element: the same as
SetIsCurrentItemAVirtualizedGroupHeader, kept for code written against this name. |
| Fields | |
CheckForVirtualizedGroupHeadersProperty | Identifies the CheckForVirtualizedGroupHeaders attached property, which asks the view to keep
IsCurrentItemAVirtualizedGroupHeaderProperty up to date on an item container. |
IsCurrentItemAVirtualizedGroupHeaderProperty | Identifies the IsCurrentItemAVirtualizedGroupHeader attached property: true
on an item container whose data is a group's header row. |
Constructors
VirtualizingCollectionView
Creates a view over a list. Add sort and group descriptions to it afterwards, as to any
ListCollectionView.
Parameters
list- The items. A list that raises change notifications, such as an
ObservableCollection, keeps the view – and the panel – up to date as it changes.
Properties
Count
Gets the number of rows in the view: the items, plus one header row for each top-level group when the view is grouped.
- Value
- The items that pass the filter, plus
GroupsCount.
Groups
Gets null, always, so that an items control lays the view out as one flat list –
with the headers among the rows – instead of generating a group item per group.
- Value
null.GroupsCountsays how many groups there are.
GroupsCount
Gets the number of top-level groups – the number of header rows among the view's rows.
- Value
- 0 when the view has no group descriptions.
Methods
GetCheckForVirtualizedGroupHeaders static
Gets whether an element is having its header-row flag kept up to date.
Parameters
obj- The item container.
Returns
true when CheckForVirtualizedGroupHeadersProperty is set on
it.
GetIsCurrentItemAVirtualizedGroupHeader static
Gets whether an item container currently holds a group's header row.
Parameters
obj- The item container.
Returns
true while it holds a header row (and is being checked).
GetItemAt
Gets the row at a position in the view: a group's header or an item.
Parameters
index- The zero-based row, counting one header row before each top-level group's items.
Returns
The CollectionViewGroup when the row is a group's header;
otherwise the item. Ungrouped, simply the item at index.
Exceptions
System.ArgumentOutOfRangeExceptionindexis negative, or not less thanCount.
IndexOf
Gets the row at which an item, or a group's header, appears – the inverse of
GetItemAt.
Parameters
item- An item, or a
CollectionViewGroupfor its header row.
Returns
The zero-based row, counting one header row before each top-level group's items; -1 when the item, or the group, is not in the view.
OnCollectionChanged
Raises the view's change notification with its positions counted in rows, header rows included, as the items control reads them.
Parameters
args- The change, with positions counted in items.
Remarks
An addition is raised at its row, preceded by the addition of its group's header row when the addition created the group. While grouped, a removal, move or replacement is raised as a reset; ungrouped, it passes through unchanged.
SetCheckForVirtualizedGroupHeaders static
Sets whether an element has its header-row flag,
IsCurrentItemAVirtualizedGroupHeaderProperty, kept up to date.
Parameters
obj- The item container – a
FrameworkElement; other elements are ignored. valuetrueto keep the flag up to date;falseto stop and clear it.
SetIsCurrentItemAVirtualizedGroupHeader static
Sets the header-row flag on an element. The view sets it itself on checked containers; there is normally no reason to call this.
Parameters
obj- The element.
value- The flag.
SetIsCurrentItemAVirtualizedGroupHeaderProperty static
Sets the header-row flag on an element: the same as
SetIsCurrentItemAVirtualizedGroupHeader, kept for code written against this name.
Parameters
obj- The element.
value- The flag.
Fields
CheckForVirtualizedGroupHeadersProperty static
Identifies the CheckForVirtualizedGroupHeaders attached property, which asks the view to keep
IsCurrentItemAVirtualizedGroupHeaderProperty up to date on an item container.
Remarks
Set it to true on the item containers, normally with a setter in the items
control's ItemContainerStyle. From then on the container follows its data context as it is
created and reused, and IsCurrentItemAVirtualizedGroupHeader is true
exactly while it holds a header row. The default is false; setting it back clears
the flag.
IsCurrentItemAVirtualizedGroupHeaderProperty static
Identifies the IsCurrentItemAVirtualizedGroupHeader attached property: true
on an item container whose data is a group's header row.
Remarks
Kept up to date only on containers with CheckForVirtualizedGroupHeadersProperty set;
elsewhere it stays false, its default. Trigger on it in the
ItemContainerStyle to style header rows apart.