Perf/smooth column resize - #420
Merged
Merged
Conversation
…eview - Widen the resize hit zone (4px -> 6px, 8px touch) so the cursor is easier to trigger near a column header edge. - Track resize drags via PointerMoved instead of ManipulationDelta for lower latency, and keep the resize cursor asserted for the whole drag instead of reverting mid-drag. - Fix cell/header misalignment after horizontal+vertical scroll followed by a sort: a recycled row container could keep a stale cell Width if it missed a Column.ActualWidth change while off-screen. - Replace real per-frame relayout during a resize drag (which capped out around 15fps regardless of row count) with a composition-only preview: cells get a per-cell Clip/RenderTransform that reveals/hides already-rendered content and shifts downstream cells, with the single real Width/ActualWidth commit happening once when the drag ends. Cells still visibly resize live, but no Measure/Arrange runs during the drag. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add TableViewColumnResizeMode with two options: Live (real relayout every frame, the default) and Preview (the composition-only illusion from the previous commit). TableViewColumnHeader now dispatches to whichever mode was active at the start of each resize drag. - Reintroduce per-frame optimizations that hadn't survived the earlier clean rebuild: skip the forced row-header remeasure, the drag-selection position cache update, and the CellsHorizontalOffset recompute while a resize is in progress — none of them depend on a data column's width, so recomputing them on every row on every drag frame was pure waste. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Document the new Live/Preview ColumnResizeMode in column-sizing.md, and point to it from performance.md's guidance on resize-drag cost. - Add a Column Resize Mode combo box to the sample app's Column Sizing page, matching the existing Column Auto Width Mode picker. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Keep the mouse resize hit zone at its original 4px; only the touch hit zone stays widened at 8px. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…lumn GetColumnDesiredWidth used to force its own unconstrained header Measure on every CalculateHeaderWidths() pass, duplicating the measure TableViewColumnHeader.MeasureOverride already does. It now reuses a cached CachedDesiredWidth from that measure instead, falling back to a forced measure only when a header hasn't been measured yet (e.g. one just added). Halves the per-Auto-column cost of every recalculation. Also skip updating the frozen-column scrollbar margin entirely when there are no frozen columns. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds configurable column-resize behavior, improving drag performance while preserving Live mode and fixing recycled-cell width alignment.
Changes:
- Adds Live and composition-based Preview resize modes.
- Removes unnecessary per-frame layout work and resynchronizes recycled cells.
- Adds tests, documentation, and a sample selector.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
tests/TableViewColumnResizingTests.cs |
Adds resize and alignment tests. |
src/TableViewRowPresenter.cs |
Skips redundant resize-time work. |
src/TableViewRow.cs |
Resynchronizes recycled cells and optimizes arrangement. |
src/TableViewHeaderRow.cs |
Caches header measurements. |
src/TableViewColumnResizeMode.cs |
Defines Live and Preview modes. |
src/TableViewColumnHeader.cs |
Implements resize gesture orchestration. |
src/TableViewCell.cs |
Implements clip/transform previews. |
src/TableView.Properties.cs |
Exposes the resize-mode property. |
src/TableView.cs |
Coordinates preview and live resizing. |
src/Columns/TableViewColumn.cs |
Tracks active resize state. |
samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml |
Demonstrates mode selection. |
docs/docs/performance.md |
Documents resize performance. |
docs/docs/column-sizing.md |
Documents mode behavior and usage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| { | ||
| if (_scrollViewer is null) return; | ||
| var frozenColumns = Columns.VisibleColumns.Where(c => c.IsFrozen); | ||
| if (_scrollViewer is null || !frozenColumns.Any()) return; |
|
|
||
| foreach (var cell in _resizingPreviewCells) | ||
| { | ||
| cell.UpdateResizePreviewClip(liveWidth, _resizingClipHeight); |
| desiredWidth += _selectionBorder?.BorderThickness.Right ?? 0; | ||
| desiredWidth += _v_gridLine?.ActualWidth ?? 0d; | ||
|
|
||
| _resizePreviewWidth = Math.Min(maxPreviewWidth, Math.Max(ActualWidth, desiredWidth)); |
Comment on lines
+417
to
+419
| var boundColumn = tableView.Columns.OfType<TableViewBoundColumn>().First(); | ||
| tableView.SortDescriptions.Add( | ||
| new ColumnSortDescription(boundColumn, boundColumn.PropertyPath, SortDirection.Ascending)); |
… border arrangement, sort test Co-authored-by: w-ahmad <17172092+w-ahmad@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Description
This is primarily a performance improvement for column resizing, plus one issue fix.
Performance improvement (the main change): dragging a column divider used to relayout every visible row's cell on every pointer-move frame, capping out around 5fps regardless of row count — the bottleneck is the number of Measure/Arrange calls crossing into the WinUI layout pipeline per frame, not extra work inside each call. This PR adds a
ColumnResizeModetoggle with two strategies:Preview— a composition-only illusion during the drag: each resized cell gets its ownClip/RenderTransformthat reveals/hides already-rendered content and shifts downstream cells, so cells still visibly resize live, but no Measure/Arrange runs until the drag ends. The real width is committed once, in a single layout pass, on release.Live— the original, fully real-time behavior (every frame is a real layout pass), now with three unrelated per-row-per-frame costs trimmed: a forced row-header remeasure, a drag-selection position cache, and aCellsHorizontalOffsetrecompute — none of which ever depended on a data column's width, so they were pure waste during a drag.Liveis the default.The fix: a recycled
TableViewRowcontainer could keep a stale cellWidthif it missed aColumn.ActualWidthchange while off-screen (e.g. an auto-width recalculation triggered by a sort), leaving cells misaligned with headers after scrolling both directions then sorting. Fixed by re-syncing width on every container reuse.Type of Change
Checklist
mainbranchScreenshots / Recordings