From 546946c8790433b1c2e2e543a9c1c35ebbaa9a8d Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Wed, 4 Dec 2024 21:23:01 +0100 Subject: [PATCH 1/3] fix: Avoid subscribing to touch scroll events twice --- .../ScrollContentPresenter.Managed.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Managed.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Managed.cs index 0c585caf63bc..bce88ecdcca5 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Managed.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Managed.cs @@ -4,6 +4,8 @@ using Windows.Devices.Input; using Windows.Foundation; using Uno.UI.Xaml; +using Uno.Disposables; + #if HAS_UNO_WINUI using _PointerDeviceType = global::Microsoft.UI.Input.PointerDeviceType; @@ -56,6 +58,8 @@ public bool CanVerticallyScroll private object RealContent => Content; + private readonly SerialDisposable _eventSubscriptions = new(); + partial void InitializePartial() { #if __SKIA__ @@ -71,6 +75,8 @@ partial void InitializePartial() private void HookScrollEvents(ScrollViewer sv) { + UnhookScrollEvents(sv); + // Note: the way WinUI does scrolling is very different, and doesn't use // PointerWheelChanged changes, etc. // We can either subscribe on the ScrollViewer or the SCP directly, but due to @@ -87,16 +93,21 @@ private void HookScrollEvents(ScrollViewer sv) ManipulationStarted += TouchScrollStarted; ManipulationDelta += UpdateTouchScroll; ManipulationCompleted += CompleteTouchScroll; + + _eventSubscriptions.Disposable = Disposable.Create(() => + { + sv.PointerWheelChanged -= PointerWheelScroll; + + ManipulationStarting -= PrepareTouchScroll; + ManipulationStarted -= TouchScrollStarted; + ManipulationDelta -= UpdateTouchScroll; + ManipulationCompleted -= CompleteTouchScroll; + }); } private void UnhookScrollEvents(ScrollViewer sv) { - sv.PointerWheelChanged -= PointerWheelScroll; - - ManipulationStarting -= PrepareTouchScroll; - ManipulationStarted -= TouchScrollStarted; - ManipulationDelta -= UpdateTouchScroll; - ManipulationCompleted -= CompleteTouchScroll; + _eventSubscriptions.Disposable = null; } private protected override void OnLoaded() From c6d067343b47fa7992df01817732d848751a1a5d Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 6 Dec 2024 15:27:18 +0100 Subject: [PATCH 2/3] test: Validate touch scrolling speed --- .../Given_ScrollViewer.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs index 1246a0e13ffb..2f2f20bbe9bb 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs @@ -1511,6 +1511,43 @@ public async Task When_SCP_Content_EmptySized_WithMargin_LayoutCycle() await UITestHelper.Load(SUT, x => x.IsLoaded); } + [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif + public async Task When_ScrollViewer_Touch_Scrolled() + { + var stackPanel = new StackPanel(); + var random = Random.Shared; + for (int i = 0; i < 10; i++) + { + stackPanel.Children.Add( + new Rectangle() + { + Width = 50, + Height = 50, + Fill = new SolidColorBrush(Color.FromArgb(255, (byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256))) + }); + } + + var SUT = new ScrollViewer + { + Height = 300, + Content = stackPanel + }; + + await UITestHelper.Load(SUT); + + var input = InputInjector.TryCreate() ?? throw new InvalidOperationException("Pointer injection not available on this platform."); + using var finger = input.GetFinger(); + var bounds = SUT.GetAbsoluteBounds(); + finger.Press(bounds.GetCenter()); + finger.MoveTo(bounds.GetCenter().Offset(0, -50)); + finger.Release(); + await WindowHelper.WaitForIdle(); + Assert.AreEqual(50, SUT.VerticalOffset); + } + [TestMethod] public async Task When_Zero_Size_With_Margin() { From d810a654f4884326b0b1454d7ce6dfc7f7b36b0f Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Wed, 11 Dec 2024 10:32:29 +0100 Subject: [PATCH 3/3] chore: Adjust condition --- .../Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs index 2f2f20bbe9bb..7526fe32838c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs @@ -1512,8 +1512,8 @@ public async Task When_SCP_Content_EmptySized_WithMargin_LayoutCycle() } [TestMethod] -#if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is not supported on this platform.")] +#if !HAS_INPUT_INJECTOR || !UNO_HAS_MANAGED_SCROLL_PRESENTER + [Ignore("This test only applies to managed scroll presenter and requires input injector.")] #endif public async Task When_ScrollViewer_Touch_Scrolled() {