Feature/20259 virtualizingdatatemplate #20267
Draft
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What does the pull request do?
This PR implements content-level virtualization for Avalonia's
ItemsControlandVirtualizingStackPanel, delivering 10-100x performance improvements for complex data templates. It introduces the newIVirtualizingDataTemplateinterface for type-aware container recycling, enabling container + child controls to be reused as a single unit rather than destroying and recreating expensive UI elements during scrolling.Additionally, this PR includes significant improvements to
VirtualizingStackPanel's scrolling behavior for heterogeneous lists (items with varying heights), reducing measure passes from 2-3 down to 1 per scroll event and eliminating scroll jumping.Key Features:
IVirtualizingDataTemplateinterface with opt-inEnableVirtualizationproperty (I would like to get rid of this, but maybe it is good for A/b testing during the pr)PersonViewModel,TaskViewModel)DataTypesetWhat is the current behavior?
Before this PR:
Limited Recycling: Only containers (
ListBoxItem,ContentPresenter) are recycled during virtualization. The content (the expensive nested UI created by data templates) is destroyed and recreated on every scroll.High Performance Cost:
Measure/Arrangecycle on every virtualization eventPoor Scrolling Performance with Heterogeneous Lists:
Memory Issues:
What is the updated/expected behavior with this PR?
After this PR:
Container-Level Virtualization:
ProductItemcontainers only reused forProductItemdata (template compatibility guaranteed)Performance Improvements:
Measure/Arrangecycles during scrollingSmooth Scrolling:
Easy Adoption:
Enable/Disable globally:
Note: I am aware that the naming
ContentVirtualizationDiagnosticsis terrible. But you may want me to delete this central way of enabling/disabling anyways.How was the solution implemented (if it's not obvious)?
Phase 1: IVirtualizingDataTemplate Interface
Created new interface for explicit content virtualization with custom recycling keys:
Implemented in
DataTemplatewithEnableVirtualizationXAML property.Phase 2: Automatic Virtualization
Templates implementing both
IRecyclingDataTemplateandITypedDataTemplatewithDataTypeset automatically benefit from pool-based recycling (default pool size: 5 controls per type).Phase 3: Container-Level Virtualization (Critical Performance Fix)
Key Insight: When virtualization is active, the child should stay attached to its container. The container + child become a single reusable unit, pooled by data type.
Implementation:
Type-Aware Container Recycling (
ItemsControl.NeedsContainerOverride):IVirtualizingDataTemplate.GetKey()for explicit recycling keysDataTypefor automatic type-safe poolingitem.GetType()for type-aware recyclingConditional Content Clearing (
ItemsControl.ClearContainerForItemOverride):Content/ContentTemplatepropertiesForced Content Update (
ItemsControl.PrepareContainerForItemOverride):SetCurrentValue(ContentProperty, item)instead ofSetIfUnsetTemplate Reuse (
ContentPresenter.CreateChild):Build()receives existing attached childnewChild == oldChildPhase 4: Smooth Scrolling Improvements
Fixed multiple measure passes during scrolling with heterogeneous items:
Eliminated Temporal Mismatch:
RealizeElements()instead of beforeSkip Redundant Re-estimation:
Direct Averaging (No Smoothing) for Larger Samples:
Preserve Estimate Tracking on Reset:
Item 0 Clipping Fix:
Phase 5: Warmup Strategy
Pre-creates and measures containers before they're needed:
Checklist
Debug.WriteLineIf()sHasUnEvenRows=trueBreaking changes
This is a fully backward-compatible enhancement with one exception:
EnableVirtualization="True"DataTypeException: If your data templates use view lifecycle events (loaded/unloaded, added/removed to/from visual/logical tree) and forward these events to their viewmodels, this behavior changes now.
Should we "fake-fire" those events for recycled controls?
Or add new events that viewmodels can listen on that work with virtualization as well?
Obsoletions / Deprecations
None.
Fixed issues
Fixes #20259