Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ protected virtual (bool VisibleItems, NSIndexPath First, NSIndexPath Center, NSI
if (collectionView is null)
return default;

var indexPathsForVisibleItems = collectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
// Sort visible item index paths by section and then by row for consistent order in both grouped and ungrouped sources
var indexPathsForVisibleItems = collectionView.IndexPathsForVisibleItems.OrderBy(x => x.Section).ThenBy(x => x.Row).ToList();

var visibleItems = indexPathsForVisibleItems.Count > 0;
NSIndexPath firstVisibleItemIndex = null, centerItemIndex = null, lastVisibleItemIndex = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ protected virtual (bool VisibleItems, NSIndexPath First, NSIndexPath Center, NSI
if (collectionView is null)
return default;

var indexPathsForVisibleItems = collectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
// Sort visible item index paths by section and then by row for consistent order in both grouped and ungrouped sources
var indexPathsForVisibleItems = collectionView.IndexPathsForVisibleItems.OrderBy(x => x.Section).ThenBy(x => x.Row).ToList();

var visibleItems = indexPathsForVisibleItems.Count > 0;
NSIndexPath firstVisibleItemIndex = null, centerItemIndex = null, lastVisibleItemIndex = null;
Expand Down
120 changes: 120 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue17664.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.Collections.ObjectModel;

namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 17664, "Incorrect ItemsViewScrolledEventArgs in CollectionView when IsGrouped is set to true", PlatformAffected.iOS)]
public class Issue17664 : ContentPage
{
CollectionView _collectionView;
Label descriptionLabel;
ObservableCollection<Issue17664_ItemModelGroup> _groupedItems;

public Issue17664()
{
Button scrollButton = new Button
{
AutomationId = "Issue17664ScrollBtn",
Text = "Scroll to Category C, Item #2"
};
scrollButton.Clicked += ScrollButton_Clicked;

descriptionLabel = new Label
{
AutomationId = "Issue17664DescriptionLabel",
Text = "Use the button above to scroll the CollectionView.",
FontSize = 14,
HorizontalOptions = LayoutOptions.Center
};

_collectionView = new CollectionView
{
IsGrouped = true,
GroupHeaderTemplate = new DataTemplate(() =>
{
Label label = new Label
{
FontAttributes = FontAttributes.Bold,
BackgroundColor = Colors.LightGray,
Padding = 10
};

label.SetBinding(Label.TextProperty, "Name");
return label;
}),
ItemTemplate = new DataTemplate(() =>
{
Label textLabel = new Label
{
FontAttributes = FontAttributes.Bold,
Padding = 30
};

textLabel.SetBinding(Label.TextProperty, ".");
return textLabel;
})
};

_collectionView.Scrolled += (s, e) =>
{
var flatItems = _groupedItems.SelectMany(group => group).ToList();
if (e.LastVisibleItemIndex >= 0 && e.LastVisibleItemIndex < flatItems.Count)
{
descriptionLabel.Text = flatItems[e.LastVisibleItemIndex];
}
};

List<string> categories = new List<string> { "Category A", "Category B", "Category C" };

_groupedItems = new ObservableCollection<Issue17664_ItemModelGroup>();

foreach (var category in categories)
{
List<string> items = new List<string>();

for (int i = 0; i < 5; i++)
{
items.Add($"{category} item #{i}");
}

_groupedItems.Add(new Issue17664_ItemModelGroup(category, items));
}

_collectionView.ItemsSource = _groupedItems;

Grid grid = new Grid
{
RowSpacing = 10,
Padding = 10,
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Star }
}
};

grid.Add(scrollButton, 0, 0);
grid.Add(descriptionLabel, 0, 1);
grid.Add(_collectionView, 0, 2);

Content = grid;
}

private void ScrollButton_Clicked(object sender, EventArgs e)
{
var targetGroup = _groupedItems.FirstOrDefault(group => group.Name == "Category C");
var targetItem = targetGroup.FirstOrDefault(item => item == "Category C item #2");

_collectionView.ScrollTo(targetItem, targetGroup, ScrollToPosition.End);
}
}

public class Issue17664_ItemModelGroup : ObservableCollection<string>
{
public string Name { get; set; }

public Issue17664_ItemModelGroup(string name, IEnumerable<string> items) : base(items)
{
Name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS // Android fix: https://github.com/dotnet/maui/pull/31437
// Windows: The Scrolled event is not consistently triggered in the CI environment during automated
// scrolling, so the label text is never updated. This is a test infrastructure limitation on Windows;
// the fix itself is iOS/MacCatalyst-only and works correctly on iOS and MacCatalyst.
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue17664 : _IssuesUITest
{
public Issue17664(TestDevice device) : base(device)
{
}

public override string Issue => "Incorrect ItemsViewScrolledEventArgs in CollectionView when IsGrouped is set to true";

[Test]
[Category(UITestCategories.CollectionView)]
public void VerifyGroupedCollectionViewVisibleItemIndices()
{
App.WaitForElement("Issue17664ScrollBtn");
App.Tap("Issue17664ScrollBtn");

var resultItem = App.WaitForElement("Issue17664DescriptionLabel").GetText();
Assert.That(resultItem, Is.EqualTo("Category C item #2"));
}
}
#endif
Loading