diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs index c7ddfc9ccaf9..3e70fd2e8c92 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs @@ -656,26 +656,25 @@ async void ScrollTo(object group, object item, ScrollToPosition toPosition, bool else semanticLocation.Bounds = new WRect(0, viewportHeight - tHeight, 0, 0); + // Waiting for loaded doesn't seem to be enough anymore; the ScrollViewer does not appear until after Loaded. + // Even if the ScrollViewer is present, an invoke at low priority fails (E_FAIL) presumably because the items are + // still loading. An invoke at idle sometimes work, but isn't reliable enough, so we'll just have to commit + // treason and use a blanket catch for the E_FAIL and try again. + try + { + List.MakeVisible(semanticLocation); + } + catch (Exception) + { + if (previouslyFailed) + return; + + Task.Delay(1).ContinueWith(ct => { ScrollTo(group, item, toPosition, shouldAnimate, includeGroup, true); }, TaskScheduler.FromCurrentSynchronizationContext()).WatchForError(); + } break; } } }); - - // Waiting for loaded doesn't seem to be enough anymore; the ScrollViewer does not appear until after Loaded. - // Even if the ScrollViewer is present, an invoke at low priority fails (E_FAIL) presumably because the items are - // still loading. An invoke at idle sometimes work, but isn't reliable enough, so we'll just have to commit - // treason and use a blanket catch for the E_FAIL and try again. - try - { - List.MakeVisible(semanticLocation); - } - catch (Exception) - { - if (previouslyFailed) - return; - - Task.Delay(1).ContinueWith(ct => { ScrollTo(group, item, toPosition, shouldAnimate, includeGroup, true); }, TaskScheduler.FromCurrentSynchronizationContext()).WatchForError(); - } } void OnElementScrollToRequested(object sender, ScrollToRequestedEventArgs e) diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionCenter.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionCenter.png new file mode 100644 index 000000000000..60b6f8b2c857 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionCenter.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionEnd.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionEnd.png new file mode 100644 index 000000000000..e22742c1a743 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionEnd.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionStart.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionStart.png new file mode 100644 index 000000000000..ef92e7785759 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue26945Test_SelectItemPositionStart.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue26945.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue26945.cs new file mode 100644 index 000000000000..9fbc46b9c9a1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue26945.cs @@ -0,0 +1,135 @@ +using System.Collections.ObjectModel; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 26945, "ListView ScrollTo position always remains at the start even when set to Center or End without animation", PlatformAffected.All)] + public class Issue26945 : ContentPage + { + private ListView ListView; + private ObservableCollection Items; + + public Issue26945() + { + Items = new ObservableCollection + { + "Item 1", + "Item 2", + "Item 3", + "Item 4", + "Item 5", + "Item 6", + "Item 7", + "Item 8", + "Item 9", + "Item 10", + "Item 11", + "Item 12", + "Item 13", + "Item 14", + "Item 15", + "Item 16", + "Item 17", + "Item 18", + "Item 19", + "Item 20", + "Item 21", + "Item 22", + "Item 23", + "Item 24", + "Item 25", + }; + + ListView = new ListView + { + ItemsSource = Items, + SelectedItem = "Item 10", + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + WidthRequest = 300, + HeightRequest = 220, + }; + + var horizontalStack = new StackLayout + { + Orientation = StackOrientation.Horizontal, + HorizontalOptions = LayoutOptions.Center, + Spacing = 20 + }; + + var startButton = new Button + { + Text = "Start", + AutomationId = "StartButton", + }; + startButton.Clicked += ScrollPositionStart_Clicked; + + var centerButton = new Button + { + Text = "Center", + AutomationId = "CenterButton", + }; + centerButton.Clicked += ScrollPositionCenter_Clicked; + + var endButton = new Button + { + Text = "End", + AutomationId = "EndButton", + }; + endButton.Clicked += ScrollPositionEnd_Clicked; + + horizontalStack.Children.Add(startButton); + horizontalStack.Children.Add(centerButton); + horizontalStack.Children.Add(endButton); + + var stackLayout = new StackLayout + { + Orientation = StackOrientation.Vertical, + Spacing = 20 + }; + + stackLayout.Children.Add(ListView); + stackLayout.Children.Add(horizontalStack); + this.Content = stackLayout; + } + + private void ScrollToSelectedItem(ScrollToPosition toPosition) + { + if (ListView?.SelectedItem != null) + { + switch (toPosition) + { + case ScrollToPosition.Start: + ListView.ScrollTo(ListView.SelectedItem, ScrollToPosition.Start, false); + break; + case ScrollToPosition.Center: + ListView.ScrollTo(ListView.SelectedItem, ScrollToPosition.Center, false); + break; + case ScrollToPosition.End: + ListView.ScrollTo(ListView.SelectedItem, ScrollToPosition.End, false); + break; + } + } + } + + private void ScrollPositionStart_Clicked(object sender, EventArgs e) + { + var currentIndex = Items.IndexOf(ListView.SelectedItem as string); + ListView.SelectedItem = Items[currentIndex + 2]; + ScrollToSelectedItem(ScrollToPosition.Start); + } + + private void ScrollPositionCenter_Clicked(object sender, EventArgs e) + { + var currentIndex = Items.IndexOf(ListView.SelectedItem as string); + ListView.SelectedItem = Items[currentIndex + 2]; + ScrollToSelectedItem(ScrollToPosition.Center); + } + + private void ScrollPositionEnd_Clicked(object sender, EventArgs e) + { + var currentIndex = Items.IndexOf(ListView.SelectedItem as string); + ListView.SelectedItem = Items[currentIndex + 2]; + ScrollToSelectedItem(ScrollToPosition.End); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionCenter.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionCenter.png new file mode 100644 index 000000000000..9ebfa07a30eb Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionCenter.png differ diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionEnd.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionEnd.png new file mode 100644 index 000000000000..159d2e9a8ac8 Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionEnd.png differ diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionStart.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionStart.png new file mode 100644 index 000000000000..4084bab10744 Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue26945Test_SelectItemPositionStart.png differ diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26945.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26945.cs new file mode 100644 index 000000000000..375e93fd8c38 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26945.cs @@ -0,0 +1,43 @@ +using NUnit.Framework; +using NUnit.Framework.Legacy; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue26945 : _IssuesUITest + { + public override string Issue => "ListView ScrollTo position always remains at the start even when set to Center or End without animation"; + + public Issue26945(TestDevice device) : base(device) + { + } + + [Test] + [Category(UITestCategories.ListView)] + public void Issue26945Test_SelectItemPositionStart() + { + App.WaitForElement("StartButton"); + App.Tap("StartButton"); + VerifyScreenshot(); + } + + [Test] + [Category(UITestCategories.ListView)] + public void Issue26945Test_SelectItemPositionCenter() + { + App.WaitForElement("CenterButton"); + App.Tap("CenterButton"); + VerifyScreenshot(); + } + + [Test] + [Category(UITestCategories.ListView)] + public void Issue26945Test_SelectItemPositionEnd() + { + App.WaitForElement("EndButton"); + App.Tap("EndButton"); + VerifyScreenshot(); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionCenter.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionCenter.png new file mode 100644 index 000000000000..c8ce2ec43735 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionCenter.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionEnd.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionEnd.png new file mode 100644 index 000000000000..67e0455cf139 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionEnd.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionStart.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionStart.png new file mode 100644 index 000000000000..ca0e5f77719a Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue26945Test_SelectItemPositionStart.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionCenter.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionCenter.png new file mode 100644 index 000000000000..1bb94efaa130 Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionCenter.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionEnd.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionEnd.png new file mode 100644 index 000000000000..ebd3bdb48d7e Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionEnd.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionStart.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionStart.png new file mode 100644 index 000000000000..1031eb08074e Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue26945Test_SelectItemPositionStart.png differ