diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs b/src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs index 59f98cda53a7..c42f5f3a4aad 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs @@ -315,11 +315,6 @@ void Move(NotifyCollectionChangedEventArgs args) int GetGroupCount(int groupIndex) { - if (groupIndex < 0 || groupIndex >= _groupSource.Count) - { - return 0; - } - switch (_groupSource[groupIndex]) { case IList list: @@ -339,11 +334,6 @@ int GetGroupCount(int groupIndex) object GetGroupItemAt(int groupIndex, int index) { - if (groupIndex < 0 || groupIndex >= _groupSource.Count) - { - return -1; - } - switch (_groupSource[groupIndex]) { case IList list: diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ObservableItemsSource.cs b/src/Controls/src/Core/Handlers/Items/iOS/ObservableItemsSource.cs index e7faa936fce3..1a8d7e7a76ac 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/ObservableItemsSource.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/ObservableItemsSource.cs @@ -314,7 +314,7 @@ void Update(Action update, NotifyCollectionChangedEventArgs ar return; var collectionView = controller.CollectionView; - if (collectionView.Hidden || collectionView.Window == null) + if (collectionView.Hidden) { return; } diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BlankScreenOnNavigationBack.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BlankScreenOnNavigationBack.png new file mode 100644 index 000000000000..3dcc839ddcf5 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/BlankScreenOnNavigationBack.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml deleted file mode 100644 index 865fb801a1e9..000000000000 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml.cs deleted file mode 100644 index 127e1eca18d0..000000000000 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue27797.xaml.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Maui.Controls.Sample.Issues; -[Issue(IssueTracker.Github, 27797, "CollectionView with grouped data crashes on iOS when the groups change", PlatformAffected.iOS)] -public class Issue27797NavigationPage : NavigationPage -{ - public Issue27797NavigationPage() : base(new Issue27797()) { } -} - -public partial class Issue27797 : ContentPage -{ - public Issue27797() - { - InitializeComponent(); - BindingContext = new MainViewModel(); - } - - private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e) - { - DetailPage detailPage = new(); - var workItemViewModel = (sender as VisualElement).BindingContext; - detailPage.BindingContext = workItemViewModel; - Navigation.PushAsync(detailPage); - } - - public class DetailPage : ContentPage - { - public DetailPage() - { - Title = "DetailPage"; - BindingContext = new WorkItemViewModel(); - - var statusLabel = new Label - { - FontAttributes = FontAttributes.Bold, - FontSize = 20, - HorizontalOptions = LayoutOptions.Center - }; - statusLabel.SetBinding(Label.TextProperty, "Status"); - - var descriptionLabel = new Label - { - FontSize = 16, - HorizontalOptions = LayoutOptions.Center - }; - descriptionLabel.SetBinding(Label.TextProperty, "Description"); - - var todoButton = new Button - { - Text = "TODO", - AutomationId = "TODO" - }; - todoButton.SetBinding(Button.CommandProperty, "ChangeStatusCommand"); - todoButton.SetBinding(Button.CommandParameterProperty, new Binding { Source = "TODO" }); - - var activeButton = new Button - { - Text = "ACTIVE", - AutomationId = "ACTIVE" - }; - activeButton.SetBinding(Button.CommandProperty, "ChangeStatusCommand"); - activeButton.SetBinding(Button.CommandParameterProperty, new Binding { Source = "ACTIVE" }); - - var doneButton = new Button - { - Text = "DONE", - AutomationId = "DONE", - }; - doneButton.SetBinding(Button.CommandProperty, "ChangeStatusCommand"); - doneButton.SetBinding(Button.CommandParameterProperty, new Binding { Source = "DONE" }); - - var buttonLayout = new HorizontalStackLayout - { - HorizontalOptions = LayoutOptions.Center, - Spacing = 5, - Children = { todoButton, activeButton, doneButton } - }; - - var mainLayout = new VerticalStackLayout - { - Spacing = 10, - Children = { statusLabel, descriptionLabel, buttonLayout } - }; - - Content = mainLayout; - } - } - - public class MainViewModel : BindableObject - { - private List _workItems = new(); - - private ObservableCollection _groupedWorkItems = new(); - public ObservableCollection GroupedWorkItems - { - get => _groupedWorkItems; - set { _groupedWorkItems = value; OnPropertyChanged(); } - } - - static readonly string StatusTODO = "TODO"; - static readonly string StatusACTIVE = "ACTIVE"; - static readonly string StatusDONE = "DONE"; - - WorkItemGroupViewModel _todoGroup = new(StatusTODO); - WorkItemGroupViewModel _activeGroup = new(StatusACTIVE); - WorkItemGroupViewModel _doneGroup = new(StatusDONE); - - public MainViewModel() - { - CreateWorkItemData(); - UpdateGroupedWorkItems(); - } - - private void UpdateGroupedWorkItems() - { - foreach (var item in _workItems) - { - if (item.Status == StatusTODO && !_todoGroup.Contains(item)) - { - _todoGroup.Add(item); - } - else if (item.Status == StatusACTIVE && !_activeGroup.Contains(item)) - { - // move any existing active item back to TODO - if (_activeGroup.Any()) - { - var currentActiveItem = _activeGroup[0]; - _activeGroup.Remove(currentActiveItem); - currentActiveItem.Status = StatusTODO; - _todoGroup.Add(currentActiveItem); - } - _activeGroup.Add(item); - } - else if (item.Status == StatusDONE && !_doneGroup.Contains(item)) - { - _doneGroup.Add(item); - } - } - - if (_todoGroup.Any()) - { - if (!GroupedWorkItems.Contains(_todoGroup)) - GroupedWorkItems.Add(_todoGroup); - } - else if (GroupedWorkItems.Contains(_todoGroup)) - { - GroupedWorkItems.Remove(_todoGroup); - } - - if (_activeGroup.Any()) - { - // ACTIVE always at top - if (!GroupedWorkItems.Contains(_activeGroup)) - GroupedWorkItems.Insert(0, _activeGroup); - } - else if (GroupedWorkItems.Contains(_activeGroup)) - { - GroupedWorkItems.Remove(_activeGroup); - } - - if (_doneGroup.Any()) - { - if (!GroupedWorkItems.Contains(_doneGroup)) - GroupedWorkItems.Add(_doneGroup); - } - else if (GroupedWorkItems.Contains(_doneGroup)) - { - GroupedWorkItems.Remove(_doneGroup); - } - } - - private bool _statusUpdatesInProgress = false; - private void WorkItem_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - if (_statusUpdatesInProgress) - return; - - if (sender is not WorkItemViewModel workItem) - return; - - if (e.PropertyName == nameof(WorkItemViewModel.Status)) - { - _statusUpdatesInProgress = true; - RemoveItemFromOldGroup(workItem); - - UpdateGroupedWorkItems(); - _statusUpdatesInProgress = false; - } - } - - private void RemoveItemFromOldGroup(WorkItemViewModel workItem) - { - if (_todoGroup.Contains(workItem)) - _todoGroup.Remove(workItem); - - if (_activeGroup.Contains(workItem)) - _activeGroup.Remove(workItem); - - if (_doneGroup.Contains(workItem)) - _doneGroup.Remove(workItem); - } - - private void CreateWorkItemData() - { - var cleanHouse = new WorkItemViewModel - { - Description = "CleanHouse", - Status = StatusDONE - }; - cleanHouse.PropertyChanged += WorkItem_PropertyChanged; - _workItems.Add(cleanHouse); - - var doLaundry = new WorkItemViewModel - { - Description = "DoLaundry", - Status = StatusDONE - }; - doLaundry.PropertyChanged += WorkItem_PropertyChanged; - _workItems.Add(doLaundry); - - var mowLawn = new WorkItemViewModel - { - Description = "MowLawn", - Status = StatusTODO - }; - mowLawn.PropertyChanged += WorkItem_PropertyChanged; - _workItems.Add(mowLawn); - - } - } - - public class WorkItemGroupViewModel : ObservableCollection - { - public WorkItemGroupViewModel(string groupDescription) - { - GroupDescription = groupDescription; - } - - public string GroupDescription { get; } - } - - public class WorkItemViewModel : BindableObject - { - private string _description; - public string Description - { - get => _description; - set { _description = value; OnPropertyChanged(); } - } - - private string _status; - public string Status - { - get => _status; - set { _status = value; OnPropertyChanged(); } - } - public Command ChangeStatusCommand => new((newStatus) => Status = newStatus); - } -} - diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28098.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue28098.xaml new file mode 100644 index 000000000000..0e940a165773 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28098.xaml @@ -0,0 +1,37 @@ + + + + + + +