diff --git a/src/Controls/src/Core/Handlers/Items/iOS/SelectableItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/SelectableItemsViewController.cs index 10acf1161a3e..357ac93cc678 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/SelectableItemsViewController.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/SelectableItemsViewController.cs @@ -53,9 +53,15 @@ internal void ClearSelection() { var selectedItemIndexes = CollectionView.GetIndexPathsForSelectedItems(); - foreach (var index in selectedItemIndexes) + if(selectedItemIndexes is not null && selectedItemIndexes.Any()) { - CollectionView.DeselectItem(index, true); + CollectionView.PerformBatchUpdates(null, _ => + { + foreach (var index in selectedItemIndexes) + { + CollectionView.DeselectItem(index, true); + } + }); } } @@ -157,8 +163,11 @@ void SynchronizePlatformSelectionWithSelectedItems() { var itemAtPath = GetItemAtIndex(path); if (!selectedItems.Contains(itemAtPath)) + { + CollectionView.PerformBatchUpdates(null, _ => { CollectionView.DeselectItem(path, true); + }); } else { diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/SelectableItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/SelectableItemsViewController2.cs index b43f06338eb0..c66335d679cd 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/SelectableItemsViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/SelectableItemsViewController2.cs @@ -40,7 +40,7 @@ internal void SelectItem(object selectedItem) if (index.Section > -1 && index.Item > -1) { - // Ensure the selected index is updated after the collection view's items generation is completed + // Ensure the selected index is updated after the collection view's items generation is completed CollectionView.PerformBatchUpdates(null, _ => { CollectionView.SelectItem(index, true, UICollectionViewScrollPosition.None); @@ -53,10 +53,13 @@ internal void ClearSelection() { var selectedItemIndexes = CollectionView.GetIndexPathsForSelectedItems(); - foreach (var index in selectedItemIndexes) + CollectionView.PerformBatchUpdates(null, _ => { - CollectionView.DeselectItem(index, true); - } + foreach (var index in selectedItemIndexes) + { + CollectionView.DeselectItem(index, true); + } + }); } void FormsSelectItem(NSIndexPath indexPath) @@ -158,7 +161,10 @@ void SynchronizePlatformSelectionWithSelectedItems() var itemAtPath = GetItemAtIndex(path); if (!selectedItems.Contains(itemAtPath)) { - CollectionView.DeselectItem(path, true); + CollectionView.PerformBatchUpdates(null, _ => + { + CollectionView.DeselectItem(path, true); + }); } else { diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SelectedItemVisualIsCleared.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SelectedItemVisualIsCleared.png new file mode 100644 index 000000000000..85b4f86db3f3 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SelectedItemVisualIsCleared.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue26187.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue26187.cs new file mode 100644 index 000000000000..46913993ad06 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue26187.cs @@ -0,0 +1,92 @@ +using System.Collections.ObjectModel; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 26187, "[MAUI] Select items traces are preserved", PlatformAffected.iOS)] + public class Issue26187 : NavigationPage + { + public Issue26187() + { + PushAsync(new CollectionViewSelectedItemNullPage()); + } + } + + public class CollectionViewSelectedItemNullPage : ContentPage + { + public ObservableCollection Items { get; set; } + + public string SelectedItem { get; set; } + + public CollectionViewSelectedItemNullPage() + { + Items = new ObservableCollection + { + "Item 1", + "Item 2", + "Item 3", + "Item 4", + "Item 5" + }; + SelectedItem = Items.LastOrDefault(); + var cv = new CollectionView + { + SelectionMode = SelectionMode.Single, + ItemTemplate = new DataTemplate(() => + { + var label = new Label + { + FontSize = 24, + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.Center, + AutomationId ="lblItem" + }; + label.SetBinding(Label.TextProperty, "."); + + return new HorizontalStackLayout + { + Children = { label } + }; + }) + + }; + + cv.SetBinding(CollectionView.ItemsSourceProperty, new Binding(nameof(Items))); + // cv.SetBinding(CollectionView.SelectedItemProperty, new Binding(nameof(SelectedItem))); + Content = cv; + + BindingContext = this; + // cv.SelectedItem = SelectedItem; + + cv.SelectionChanged += CollectionView_SelectionChanged; + } + + async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (e.CurrentSelection.FirstOrDefault() is string issue) + { + await Navigation.PushAsync(new NewPage(issue)); + } + + // Clear Selection + var cv = sender as CollectionView; + if (cv is not null) + { + cv.SelectedItem = null; + } + } + + class NewPage : ContentPage + { + public NewPage(string item) + { + Title = item; + Content = new Button + { + Text = $"Go Back Selected Item null from {item}", + Command = new Command(() => Navigation.PopAsync()), + AutomationId = "btnGoBack" + }; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26187.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26187.cs new file mode 100644 index 000000000000..42f7c2eda424 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26187.cs @@ -0,0 +1,27 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue26187 : _IssuesUITest + { + public override string Issue => "[MAUI] Select items traces are preserved"; + + public Issue26187(TestDevice device) + : base(device) + { } + + [Test] + [Category(UITestCategories.CollectionView)] + public void SelectedItemVisualIsCleared() + { + App.WaitForElement("lblItem"); + App.Tap("lblItem"); + App.WaitForElement("btnGoBack"); + App.Tap("btnGoBack"); + App.WaitForElement("lblItem"); + VerifyScreenshot(); + } + } +} diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SelectedItemVisualIsCleared.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SelectedItemVisualIsCleared.png new file mode 100644 index 000000000000..65b21b80dcbe Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SelectedItemVisualIsCleared.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SelectedItemVisualIsCleared.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SelectedItemVisualIsCleared.png new file mode 100644 index 000000000000..4ab9eaef03b5 Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SelectedItemVisualIsCleared.png differ