From 69922b69176e12fcbeef147e596e57ec9612583c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 5 May 2023 13:52:01 +0200 Subject: [PATCH] Adjust thumb drag position on track size change. Fixes `ScrollViewer` jumping around when the scroll extent changes while dragging the scrollbar thumb. --- src/Avalonia.Controls/Primitives/Thumb.cs | 6 ++++++ src/Avalonia.Controls/Primitives/Track.cs | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Thumb.cs b/src/Avalonia.Controls/Primitives/Thumb.cs index 13f4fdd534..c5d73dc00f 100644 --- a/src/Avalonia.Controls/Primitives/Thumb.cs +++ b/src/Avalonia.Controls/Primitives/Thumb.cs @@ -46,6 +46,12 @@ namespace Avalonia.Controls.Primitives remove { RemoveHandler(DragCompletedEvent, value); } } + internal void AdjustDrag(Vector v) + { + if (_lastPoint.HasValue) + _lastPoint = _lastPoint.Value + v; + } + protected override AutomationPeer OnCreateAutomationPeer() => new ThumbAutomationPeer(this); protected virtual void OnDragStarted(VectorEventArgs e) diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs index fe4912a33c..913dd83c16 100644 --- a/src/Avalonia.Controls/Primitives/Track.cs +++ b/src/Avalonia.Controls/Primitives/Track.cs @@ -45,6 +45,8 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty IgnoreThumbDragProperty = AvaloniaProperty.Register(nameof(IgnoreThumbDrag)); + private Vector _lastDrag; + static Track() { ThumbProperty.Changed.AddClassHandler((x, e) => x.ThumbChanged(e)); @@ -245,7 +247,10 @@ namespace Avalonia.Controls.Primitives if (Thumb != null) { - Thumb.Arrange(new Rect(offset, pieceSize)); + var bounds = new Rect(offset, pieceSize); + var adjust = CalculateThumbAdjustment(Thumb, bounds); + Thumb.Arrange(bounds); + Thumb.AdjustDrag(adjust); } ThumbCenterOffset = offset.Y + (thumbLength * 0.5); @@ -277,15 +282,25 @@ namespace Avalonia.Controls.Primitives if (Thumb != null) { - Thumb.Arrange(new Rect(offset, pieceSize)); + var bounds = new Rect(offset, pieceSize); + var adjust = CalculateThumbAdjustment(Thumb, bounds); + Thumb.Arrange(bounds); + Thumb.AdjustDrag(adjust); } ThumbCenterOffset = offset.X + (thumbLength * 0.5); } + _lastDrag = default; return arrangeSize; } + private Vector CalculateThumbAdjustment(Thumb thumb, Rect newThumbBounds) + { + var thumbDelta = newThumbBounds.Position - thumb.Bounds.Position; + return _lastDrag - thumbDelta; + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); @@ -444,6 +459,7 @@ namespace Avalonia.Controls.Primitives Value + ValueFromDistance(e.Vector.X, e.Vector.Y), Minimum, Maximum)); + _lastDrag = e.Vector; } private void ShowChildren(bool visible)