Skip to content

Feature/drag selection rectangle#344

Open
godlytalias wants to merge 6 commits intow-ahmad:mainfrom
godlytalias:feature/drag_selection_rectangle
Open

Feature/drag selection rectangle#344
godlytalias wants to merge 6 commits intow-ahmad:mainfrom
godlytalias:feature/drag_selection_rectangle

Conversation

@godlytalias
Copy link
Copy Markdown

@godlytalias godlytalias commented Apr 9, 2026

Add Drag Selection Rectangle ( #334 )

Adds a semi-transparent rectangle overlay during cell/row drag selection, providing visual feedback similar to File Explorer's drag-select experience.

DragSelection.mp4

Feature Overview

  • Visual drag rectangle — A semi-transparent accent-colored rectangle follows the mouse from the drag start point to the current pointer position, clamped to the viewport. The rectangle extends naturally when content scrolls (start point adjusts for scroll offset).
  • Auto-scroll — When the pointer is near the top/bottom/left/right edges during drag, the view auto-scrolls with speed proportional to edge proximity. Vertical scroll uses a DispatcherTimer (16ms/~60fps) with ScrollViewer.ChangeView; horizontal scroll uses the existing HorizontalOffset DP pattern.
  • Scroll-sync — Selection updates for newly visible rows during auto-scroll or mouse-wheel scroll via ScrollViewer.ViewChanged handler with hit-test at the clamped pointer position.
  • ShowDragRectangle property — New bool dependency property (default: true) to enable/disable the rectangle. Setting to false mid-drag correctly tears down the rectangle. The underlying drag selection behavior (cell/row selection via pointer movement) is unaffected by this property.

Files Changed

File Change
src/TableView.Properties.cs ShowDragRectangle DP + property changed callback
src/TableView.cs Drag rectangle fields, StartDragRectangle, UpdateDragRectangleVisual, PositionDragRectangle, auto-scroll timer, ViewChanged handler, FindCellAtCanvasPoint, EndDragRectangle cleanup, OnCurrentCellChanged drag optimization, OnCellSelectionChanged coalescing, OnUnloaded cleanup
src/TableViewCell.cs OnPointerPressed starts drag, OnPointerReleased ends drag, OnPointerCaptureLost safety net, OnManipulationDelta updates rectangle visual, TransformPointToCanvas helper, ApplyCurrentCellState(skipFocus)
src/Themes/Resources.xaml Theme resources for Light, Dark, HighContrast (fill, stroke, corner radius)
src/Themes/TableView.xaml Canvas + Border overlay in control template (Grid.Row="1", IsHitTestVisible="False")
samples/.../SelectionPage.xaml ShowDragRectangle ToggleSwitch + code substitution
tests/DragSelectionRectangleTests.cs 16 unit tests covering property defaults, drag lifecycle, selection mode guards, idempotency

Lifecycle

PointerPressed → CapturePointer + StartDragRectangle (hook ViewChanged, init state)
ManipulationDelta → UpdateDragRectangleVisual (position rectangle + auto-scroll)
                  → FindCell + MakeSelection (same path as non-rectangle)
ViewChanged → PositionDragRectangle (adjust for scroll) + FindCellAtCanvasPoint + MakeSelection
PointerReleased → EndDragRectangle (stop timer, unhook events, restore focus/scroll)
PointerCaptureLost → EndDragRectangle (safety net)

Signed-off-by: Godly Alias <godlyalias@microsoft.com>
Signed-off-by: Godly Alias <godlyalias@microsoft.com>
Signed-off-by: Godly Alias <godlyalias@microsoft.com>
Signed-off-by: Godly Alias <godlyalias@microsoft.com>
Signed-off-by: Godly Alias <godlyalias@microsoft.com>
@w-ahmad
Copy link
Copy Markdown
Owner

w-ahmad commented Apr 10, 2026

Thanks for the PR @godlytalias, it looks great. Quick question: can we enable auto-scroll even when ShowDragRectangle is set to false? Currently the selection stops at the last visible cell without the drag rectangle.

20260410-2140-19 2165094

@godlytalias
Copy link
Copy Markdown
Author

Thanks for the PR @godlytalias, it looks great. Quick question: can we enable auto-scroll even when ShowDragRectangle is set to false? Currently the selection stops at the last visible cell without the drag rectangle.

20260410-2140-19 2165094 20260410-2140-19 2165094

@w-ahmad Sounds good, I guess we should then expose a property for devs to toggle it and have to keep it disabled by default for not breaking current behavior? We can enable the behavior only when DragSelectionRectangle being enabled? Or do you have different opinion?

@w-ahmad
Copy link
Copy Markdown
Owner

w-ahmad commented Apr 12, 2026

@w-ahmad Sounds good, I guess we should then expose a property for devs to toggle it and have to keep it disabled by default for not breaking current behavior? We can enable the behavior only when DragSelectionRectangle being enabled? Or do you have different opinion?

I think the auto-scroll must be there even when the DragSelectionRectangle is not visible and there is no need to add property to turn it on or off. This is because most DataGrid controls (tried on WPF and Synfusion) and even Excel offers it by default. The DragSelectionRectangle is a new feature for TableView, for which you’ve already added a flag property to turn it on or off.

@w-ahmad w-ahmad linked an issue Apr 12, 2026 that may be closed by this pull request
@godlytalias
Copy link
Copy Markdown
Author

@w-ahmad Sounds good, I guess we should then expose a property for devs to toggle it and have to keep it disabled by default for not breaking current behavior? We can enable the behavior only when DragSelectionRectangle being enabled? Or do you have different opinion?

I think the auto-scroll must be there even when the DragSelectionRectangle is not visible and there is no need to add property to turn it on or off. This is because most DataGrid controls (tried on WPF and Synfusion) and even Excel offers it by default. The DragSelectionRectangle is a new feature for TableView, for which you’ve already added a flag property to turn it on or off.

Okay sure, I will keep the autoscroll turned on by default then. Thanks

Signed-off-by: Godly Alias <godlyalias@microsoft.com>
Comment thread src/TableView.cs
/// <summary>
/// Identifies the <see cref="ShowDragRectangle"/> dependency property.
/// </summary>
public static readonly DependencyProperty ShowDragRectangleProperty = DependencyProperty.Register(nameof(ShowDragRectangle), typeof(bool), typeof(TableView), new PropertyMetadata(false, OnShowDragRectangleChanged));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's set the default value to true.

Comment thread src/TableView.cs
_dragRectangle.Width = 0;
_dragRectangle.Height = 0;

_dragRectangle.Visibility = Visibility.Visible;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest setting the visibility on the drag canvas itself to reduce the number of elements loading at the start and if ShowDragRectangle is set to false, the canvas won’t load at all.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually even if we keep visibility as 'collapsed', the element would still be loaded just that it won't participate in rendering, https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.uielement.visibility?view=winrt-28000#remarks

If the concern is about reducing elements, we may have to add logic for x:load here

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting. I'll leave it up to you—if there's no need to set the visibility on the canvas itself, then keep it as is. If you think x:Load could make a difference, go ahead and use it.

Comment thread src/TableView.cs
private bool _ensureColumns = true;
private readonly List<TableViewRow> _rows = [];
private readonly CollectionView _collectionView = [];
internal Canvas? _dragRectangleCanvas;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making a field internal feels a bit unusual.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it internal as these fields are to be accessed by TableViewCell class as well but not to be exposed outside the assembly. Whether you think differently?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, let’s turn them into internal properties then.

Comment thread src/TableView.cs
internal Canvas? _dragRectangleCanvas;
private Border? _dragRectangle;
private Point? _dragStartPoint;
internal bool _isDragSelecting;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making a field internal feels a bit unusual.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drag Selection Rectangle (Rubber-Band Selection)

2 participants