From f632a3e95db9849941e13285dbea3ba9dfc580e4 Mon Sep 17 00:00:00 2001 From: Matthew Rajala Date: Mon, 25 Nov 2024 13:18:20 -0500 Subject: [PATCH 1/2] chore: scrollviewer offset solution --- .../Given_CalendarView.cs | 38 +++++++++++++++++++ ...CalendarPanel.ModernCollectionBasePanel.cs | 10 ++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CalendarView.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CalendarView.cs index 851a539b1ddd..4b29f020d760 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CalendarView.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CalendarView.cs @@ -24,6 +24,8 @@ namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls; [RunsOnUIThread] public class Given_CalendarView { + const int DEFAULT_MIN_MAX_DATE_YEAR_OFFSET = 100; + [TestMethod] [UnoWorkItem("https://github.com/unoplatform/uno/issues/16123")] [Ignore("Test is unstable on CI: https://github.com/unoplatform/uno/issues/16123")] @@ -61,6 +63,42 @@ public async Task When_MinDate_Has_Different_Offset() await UITestHelper.Load(calendarView); } + [TestMethod] + public async Task When_Scroll_To_MaxDate() + { + var calendarView = new CalendarView() + { + DisplayMode = CalendarViewDisplayMode.Decade + }; + + await UITestHelper.Load(calendarView); + + Type calendarViewType = typeof(CalendarView); + MethodInfo ChangeVisualStateInfo = calendarViewType.GetMethod("ChangeVisualState", BindingFlags.NonPublic | BindingFlags.Instance); + + // Scroll to max date + calendarView.SetDisplayDate(calendarView.MaxDate); + + // Switch to Year view + calendarView.DisplayMode = CalendarViewDisplayMode.Year; + ChangeVisualStateInfo.Invoke(calendarView, new object[] { false }); + await TestServices.WindowHelper.WaitForIdle(); + + // Switch back to Decade view + calendarView.DisplayMode = CalendarViewDisplayMode.Decade; + ChangeVisualStateInfo.Invoke(calendarView, new object[] { false }); + await TestServices.WindowHelper.WaitForIdle(); + + // Decade viewport should be full of items (no missing row) + calendarView.GetActiveGeneratorHost(out var pHost); + var maxDecadeIndex = DEFAULT_MIN_MAX_DATE_YEAR_OFFSET * 2; + var maxDisplayedItems = pHost.Panel.Rows * pHost.Panel.Cols; + + // The first visible index should be less than the max possible index minus the max items we can display + // Worst case scenario is that the last row only has 1 item + Assert.IsTrue(pHost.Panel.FirstVisibleIndex <= maxDecadeIndex - (maxDisplayedItems - pHost.Panel.Rows - 1)); + } + #if __WASM__ [TestMethod] [Ignore("Fails on Fluent styles #17272")] diff --git a/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs b/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs index 7cd5d8476da8..1fe4bc3120e5 100644 --- a/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs @@ -432,7 +432,15 @@ internal void ScrollItemIntoView(int index, ScrollIntoViewAlignment alignment, d // then it will request GetContainerFromIndex and tries to focus it. // So here we prepare the _effectiveViewport (which will most probably be re-updated by the ChangeView below), // and then force a base_Measure() - _effectiveViewport.Y += newOffset - currentOffset; + + if (newOffset >= sv.ScrollableHeight) + { + _effectiveViewport.Y = currentOffset; + } + else + { + _effectiveViewport.Y += newOffset - currentOffset; + } sv.ChangeView( horizontalOffset: null, From 16ca3fbf4aa8ad28f80a459ce49c14f6cae8778e Mon Sep 17 00:00:00 2001 From: Matthew Rajala Date: Thu, 5 Dec 2024 10:42:41 -0500 Subject: [PATCH 2/2] chore: add issue mention --- .../Primitives/CalendarPanel.ModernCollectionBasePanel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs b/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs index 1fe4bc3120e5..7befaaec8e9f 100644 --- a/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/CalendarView/Primitives/CalendarPanel.ModernCollectionBasePanel.cs @@ -433,6 +433,9 @@ internal void ScrollItemIntoView(int index, ScrollIntoViewAlignment alignment, d // So here we prepare the _effectiveViewport (which will most probably be re-updated by the ChangeView below), // and then force a base_Measure() +#if HAS_UNO + // Scrolling to the MaxDate and switching between Decade/Year/Month views keeps increasing the _effectiveViewport.Y + // even though there's no more items to show after MaxDate, causing empty rows in the viewport if (newOffset >= sv.ScrollableHeight) { _effectiveViewport.Y = currentOffset; @@ -441,6 +444,9 @@ internal void ScrollItemIntoView(int index, ScrollIntoViewAlignment alignment, d { _effectiveViewport.Y += newOffset - currentOffset; } +#else + _effectiveViewport.Y += newOffset - currentOffset; +#endif sv.ChangeView( horizontalOffset: null,