CollectionView with grouping show duplicates groups or crash when adding/removing data on iOS and MacCatalyst
daniel-c opened this issue ยท 22 comments
Description
A CollectionView with IsGrouped set to True results in a wrong view rendering with duplicate groups when data is added, usually if not at the top scroll position. It crashes sometimes when data is removed. This happen on iOS and MacCatalyst. It works correctly on Android.
This may be related to issue #14978
Simulator.Screen.Recording.-.iPhone.15.Pro.-.2023-10-12.at.11.12.06.mp4
Steps to Reproduce
- Deploy the sample project on iOS Simulator or on Mac.
- Scroll a bit down the displayed list
- Click 'Add' to add items to the list and observe the rendering of duplicate groups.
- Click 'Clear' to reset the list: the app crash or display empty groups.
Link to public reproduction project repository
https://github.com/daniel-c/MauiGroupedCollectionTest.git
Version with bug
8.0.0-rc.1.9171
Is this a regression from previous behavior?
Not sure, did not test other versions
Last version that worked well
Unknown/Other
Affected platforms
iOS, macOS
Affected platform versions
iOS 17, macOS 14.0
Did you find any workaround?
No
Relevant log output
ObjCRuntime.ObjCException: Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Invalid batch updates detected: the number of sections and/or items returned by the data source before and after performing the batch updates are inconsistent with the updates.
Data source before updates = { 1 section with item counts: [1] }
Data source after updates = { 1 section with item counts: [1] }
Updates = [
Insert item (0 - 0)
]
Collection view: <UICollectionView: 0x138bba800; frame = (0 0; 393 754.333); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000c689f0>; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x6000006edf20>; contentOffset: {0, 0}; contentSize: {393, 134}; adjustedContentInset: {0, 0, 0, 0}; layout: <Microsoft_Maui_Controls_Handlers_Items_ListViewLayout: 0x132374fc0>; dataSource: <Microsoft_Maui_Controls_Handlers_Items_ReorderableItemsViewController_1: 0x13235cac0>>
Native stack trace:
0 CoreFoundation 0x00007ff80048d28d __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007ff800057894 objc_exception_throw + 48
2 Foundation 0x00007ff800da2c80 _userInfoForFileAndLine + 0
3 UIKitCore 0x000000012068c0a7 -[UICollectionView _Bug_Detected_In_Client_Of_UICollectionView_Invalid_Batch_Updates:] + 115
4 UIKitCore 0x000000012068b2bc -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:collectionViewAnimator:] + 13332
5 UIKitCore 0x0000000120686fec -[UICollectionView _updateRowsAtIndexPaths:updateAction:updates:] + 492
6 UIKitCore 0x00000001206870d2 -[UICollectionView insertItemsAtIndexPaths:] + 64
7 libxamarin-dotnet-debug.dylib 0x000000010e73e0a9 xamarin_dyn_objc_msgSend + 217
8 libmonosgen-2.0.dylib 0x000000010ee96db1 do_icall + 193
9 libmonosgen-2.0.dylib 0x000000010ee955d7 do_icall_wrapper + 295
10 libmonosgen-2.0.dylib 0x000000010ee862f6 mono_interp_exec_method + 3990
11 libmonosgen-2.0.dylib 0x000000010ee83a63 interp_runtime_invoke + 259
12 libmonosgen-2.0.dylib 0x000000010ef6aaed mono_runtime_try_invoke + 157
13 libmonosgen-2.0.dylib 0x000000010ef6deae mono_runtime_invoke + 478
14 TestCollectionView 0x000000010ce571a5 _ZL31native_to_managed_trampoline_10P11objc_objectP13objc_selectorPP11_MonoMethodS0_j + 469
15 TestCollectionView 0x000000010cec19f2 -[UIKit_UIBarButtonItem_Callback InvokeAction:] + 50
16 UIKitCore 0x00000001212514c6 -[UIApplication sendAction:to:from:forEvent:] + 95
17 UIKitCore 0x00000001204682d9 -[UIBarButtonItem _triggerActionForEvent:fallbackSender:] + 267
18 UIKitCore 0x00000001204381bb __45-[_UIButtonBarTargetAction _invoke:forEvent:]_block_invoke + 39
19 UIKitCore 0x0000000120438068 -[_UIButtonBarTargetAction _invoke:forEvent:] + 152
20 UIKitCore 0x00000001212514c6 -[UIApplication sendAction:to:from:forEvent:] + 95
21 UIKitCore 0x00000001208e92f3 -[UIControl sendAction:to:forEvent:] + 112
22 UIKitCore 0x00000001208e96e8 -[UIControl _sendActionsForEvents:withEvent:] + 334
23 UIKitCore 0x00000001208e9744 -[UIControl _sendActionsForEvents:withEvent:] + 426
24 UIKitCore 0x00000001208e7f79 -[UIControl touchesEnded:withEvent:] + 485
25 UIKitCore 0x0000000121294ae8 -[UIWindow _sendTouchesForEvent:] + 1261
26 UIKitCore 0x0000000121296c54 -[UIWindow sendEvent:] + 5284
27 UIKitCore 0x000000012126be6c -[UIApplication sendEvent:] + 772
28 UIKitCore 0x0000000121318b99 __dispatchPreprocessedEventFromEventQueue + 8406
29 UIKitCore 0x000000012131b455 __processEventQueue + 8414
30 UIKitCore 0x00000001213118d6 __eventFetcherSourceCallback + 163
31 CoreFoundation 0x00007ff8003e9d0f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
32 CoreFoundation 0x00007ff8003e9c51 __CFRunLoopDoSource0 + 157
33 CoreFoundation 0x00007ff8003e944e __CFRunLoopDoSources0 + 215
34 CoreFoundation 0x00007ff8003e3b83 __CFRunLoopRun + 919
35 CoreFoundation 0x00007ff8003e3409 CFRunLoopRunSpecific + 557
36 GraphicsServices 0x00007ff80a650187 GSEventRunModal + 137
37 UIKitCore 0x000000012124b3a2 -[UIApplication _run] + 972
38 UIKitCore 0x000000012124fe10 UIApplicationMain + 123
39 libxamarin-dotnet-debug.dylib 0x000000010e6f847a xamarin_UIApplicationMain + 58
40 libmonosgen-2.0.dylib 0x000000010ee96e45 do_icall + 341
41 libmonosgen-2.0.dylib 0x000000010ee955d7 do_icall_wrapper + 295
42 libmonosgen-2.0.dylib 0x000000010ee862f6 mono_interp_exec_method + 3990
43 libmonosgen-2.0.dylib 0x000000010ee83a63 interp_runtime_invoke + 259
44 libmonosgen-2.0.dylib 0x000000010ef69b68 mono_runtime_invoke_checked + 136
45 libmonosgen-2.0.dylib 0x000000010ef7133b mono_runtime_exec_main_checked + 107
46 libmonosgen-2.0.dylib 0x000000010edd61d2 mono_jit_exec + 354
47 libxamarin-dotnet-debug.dylib 0x000000010e73cbca xamarin_main + 1898
48 TestCollectionView 0x000000010ceea694 main + 68
49 dyld 0x000000010d7023ee start_sim + 10
50 ??? 0x00000001189493a6 0x0 + 4707357606
Native stack trace:
0 CoreFoundation 0x00007ff80048d28d __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007ff800057894 objc_exception_throw + 48
2 Foundation 0x00007ff800da2c80 _userInfoForFileAndLine + 0
3 UIKitCore 0x000000012068c0a7 -[UICollectionView _Bug_Detected_In_Client_Of_UICollectionView_Invalid_Batch_Updates:] + 115
4 UIKitCore 0x000000012068b2bc -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:collectionViewAnimator:] + 13332
5 UIKitCore 0x0000000120686fec -[UICollectionView _updateRowsAtIndexPaths:updateAction:updates:] + 492
6 UIKitCore 0x00000001206870d2 -[UICollectionView insertItemsAtIndexPaths:] + 64
7 libxamarin-dotnet-debug.dylib 0x000000010e73e0a9 xamarin_dyn_objc_msgSend + 217
8 libmonosgen-2.0.dylib 0x000000010ee96db1 do_icall + 193
9 libmonosgen-2.0.dylib 0x000000010ee955d7 do_icall_wrapper + 295
10 libmonosgen-2.0.dylib 0x000000010ee862f6 mono_interp_exec_method + 3990
11 libmonosgen-2.0.dylib 0x000000010ee83a63 interp_runtime_invoke + 259
12 libmonosgen-2.0.dylib 0x000000010ef6aaed mono_runtime_try_invoke + 157
13 libmonosgen-2.0.dylib 0x000000010ef6deae mono_runtime_invoke + 478
14 TestCollectionView 0x000000010ce571a5 _ZL31native_to_managed_trampoline_10P11objc_objectP13objc_selectorPP11_MonoMethodS0_j + 469
15 TestCollectionView 0x000000010cec19f2 -[UIKit_UIBarButtonItem_Callback InvokeAction:] + 50
16 UIKitCore 0x00000001212514c6 -[UIApplication sendAction:to:from:forEvent:] + 95
17 UIKitCore 0x00000001204682d9 -[UIBarButtonItem _triggerActionForEvent:fallbackSender:] + 267
18 UIKitCore 0x00000001204381bb __45-[_UIButtonBarTargetAction _invoke:forEvent:]_block_invoke + 39
19 UIKitCore 0x0000000120438068 -[_UIButtonBarTargetAction _invoke:forEvent:] + 152
20 UIKitCore 0x00000001212514c6 -[UIApplication sendAction:to:from:forEvent:] + 95
21 UIKitCore 0x00000001208e92f3 -[UIControl sendAction:to:forEvent:] + 112
22 UIKitCore 0x00000001208e96e8 -[UIControl _sendActionsForEvents:withEvent:] + 334
23 UIKitCore 0x00000001208e9744 -[UIControl _sendActionsForEvents:withEvent:] + 426
24 UIKitCore 0x00000001208e7f79 -[UIControl touchesEnded:withEvent:] + 485
25 UIKitCore 0x0000000121294ae8 -[UIWindow _sendTouchesForEvent:] + 1261
26 UIKitCore 0x0000000121296c54 -[UIWindow sendEvent:] + 5284
27 UIKitCore 0x000000012126be6c -[UIApplication sendEvent:] + 772
28 UIKitCore 0x0000000121318b99 __dispatchPreprocessedEventFromEventQueue + 8406
29 UIKitCore 0x000000012131b455 __processEventQueue + 8414
30 UIKitCore 0x00000001213118d6 __eventFetcherSourceCallback + 163
31 CoreFoundation 0x00007ff8003e9d0f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
32 CoreFoundation 0x00007ff8003e9c51 __CFRunLoopDoSource0 + 157
33 CoreFoundation 0x00007ff8003e944e __CFRunLoopDoSources0 + 215
34 CoreFoundation 0x00007ff8003e3b83 __CFRunLoopRun + 919
35 CoreFoundation 0x00007ff8003e3409 CFRunLoopRunSpecific + 557
36 GraphicsServices 0x00007ff80a650187 GSEventRunModal + 137
37 UIKitCore 0x000000012124b3a2 -[UIApplication _run] + 972
38 UIKitCore 0x000000012124fe10 UIApplicationMain + 123
39 libxamarin-dotnet-debug.dylib 0x000000010e6f847a xamarin_UIApplicationMain + 58
40 libmonosgen-2.0.dylib 0x000000010ee96e45 do_icall + 341
41 libmonosgen-2.0.dylib 0x000000010ee955d7 do_icall_wrapper + 295
42 libmonosgen-2.0.dylib 0x000000010ee862f6 mono_interp_exec_method + 3990
43 libmonosgen-2.0.dylib 0x000000010ee83a63 interp_runtime_invoke + 259
44 libmonosgen-2.0.dylib 0x000000010ef69b68 mono_runtime_invoke_checked + 136
45 libmonosgen-2.0.dylib 0x000000010ef7133b mono_runtime_exec_main_checked + 107
46 libmonosgen-2.0.dylib 0x000000010edd61d2 mono_jit_exec + 354
47 libxamarin-dotnet-debug.dylib 0x000000010e73cbca xamarin_main + 1898
48 TestCollectionView 0x000000010ceea694 main + 68
49 dyld 0x000000010d7023ee start_sim + 10
50 ??? 0x00000001189493a6 0x0 + 4707357606
Collection view appears to be completely broken on iOS in .NET 8 and the latest .NET 7 SR. In additional to the bug listed in this issue, scrolling performance is very bad and memory usage goes through the roof when scrolling the collection view. It almost seems like views are not getting recycled and are being recreated. This used to work fine in .NET 7 before the latest service release.
It baffles me to see what's going on with MAUI. Why is it so hard to get basic controls working without issues?
This is related to #16877.
Can someone take a look at this issue for the .NET 8 release?
I just tested this on an iPhone 12 Pro running iOS 16.7.1 and did not notice the problem. The problem occurs for me on an iPhone 15 Pro running iOS 17.0.3. Based on that, I don't think this is a regression in the collection view. I think this is caused by some change in iOS 17.
Verified this on Visual Studio Enterprise 17.9.0 Preview 1(8.0.3). Repro on iOS 17.0 and MacCatalyst, not repro on Android 14.0-API34 with below Project:
MauiGroupedCollectionTest.zip
On Windows: Run failed with below exception.
The value "TestCollectionView.ViewModels.AnimalGroup" is not of type "TestCollectionView.ViewModels.Animal" and cannot be used in this generic collection. (Parameter 'value')
My workaround is to reinitialize a new CollectionView each time the underlying data changes, rather than relying on a single CollectionView with a dynamically changing ItemSource. It works well on Android to change the ItemsSource, but for some reason on iOS it doesn't play nice with changing groups.
I'm seeing duplicate groups when the CollectionView goes from having 2 groups down to 1 group. Its only a problem on iOS. Not seeing problems when there is only ever 1 group.
My setup is...
- iPhone Xr running iOS 16.7.2
- MAUI workload 7.0.96
- CollectionView displaying 2 groups with 1+ items
- Filter out items such that we only have 1 group now
Here's a screenshot with black boxes as an example. In the 2nd screenshot it should only be displaying the "Older" group but for some reason it displays that group twice and the 2nd group has an empty slot.
The issue dissapeared for me when i set the HeightRequest on the root element in the ItemTemplate and the GroupHeaderTemplate
I am also facing the same issue. We have a large enterprise application in Xamarin Forms. We planned to migrate it to MAUI in Q1-24. But this issue is stopping me from moving further, as my completed app depends on the Exaplandable Collection View.
Even I checked with .NET 8 latest release but still reproducing.
Can you please take this as a priority item?
We faced this issue too after upgrade to .NET 8.0. We have group collection view and 2 buttons that navigates between weeks. The combination of scroll a tap button event clears data, but headers one covers old one. This affects iOS release. And yes, collection view performance is terrible in release. Items in collection ~8.
UPD: Upgrade MAUI libraries to 8.0.14 or 8.0.20-nightly significantly increased Group CollectionView performance and responsiveness. And glitch with overlapping headers seems to disappear.
I am facing the same issue with nightly build of 8.0.20. Did you try the workaround described above or without? Is this still a way to go with the above?
I am facing the same issue with nightly build of 8.0.20. Did you try the workaround described above or without? Is this still a way to go with the above?
Yes, i setup fixed height for header template and data template in collection view
Thanks, then I will give it a try. First of all I was thinking, that my queries to get the grouped ObservableRangeCollection
was somehow wrong. But, I figured out there was just one element in one of my groups and it showed two group headers. Even when I have an empty grouped ObservableRangeCollection
, I can see 2 empty headers.
I could figure it out, how I could get my scenario working. Just wanted to share it, in case somebody else needs ideas what to try to get the own scenario working.
This is how it behaved before:
<Grid RowDefinitions="Auto, *">
<searchBarControl:SearchBarLang Grid.Row="0" ios:SearchBar.SearchBarStyle="Minimal" Text="{Binding SearchText}" Placeholder="Search item..." CancelButtonText="{loc:Translate CancelButtonText}" Margin="0, 10, 0, 5"/>
<CollectionView Grid.Row="1" ItemsSource="{Binding GroupedItems, Mode=OneWay}" VerticalScrollBarVisibility="Always" IsGrouped="True" Margin="0, 0, 0, 50">
<!-- Group Header Template: Titles of a Group -->
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="viewModels:GroupedSelectionItemList">
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
<Label FontSize="16" FontAttributes="Bold" Text="{Binding GroupName, StringFormat=' {0}'}" TextColor="{StaticResource Blue100Accent}" Margin="0, 25, 0, 0" />
<BoxView HeightRequest="0.5" Color="{StaticResource Gray200}" HorizontalOptions="FillAndExpand" Margin="0, 5, 0, 5" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<!-- Item Template: Selected Item -->
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="{x:Type databaseModels:ItemSelection}">
<Grid ColumnDefinitions="*, Auto" RowDefinitions="Auto" Padding="{OnPlatform Default='5, 0, 5, 0', iOS='5, 0, 5, 10'}">
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Item.Name}" VerticalOptions="Center" />
<Switch Grid.Row="0" Grid.Column="1" IsEnabled="True" IsToggled="{Binding IsSelected, Mode=TwoWay}" ThumbColor="{StaticResource Gray100}" OnColor="{StaticResource DarkOrange1}" VerticalOptions="Center" HorizontalOptions="Center" Margin="{OnPlatform Android='0, -5, 0, -5'}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
With this change it went to this:
<Grid RowDefinitions="Auto, Auto">
<searchBarControl:SearchBarLang Grid.Row="0" ios:SearchBar.SearchBarStyle="Minimal" Text="{Binding SearchText}" Placeholder="Search item..." CancelButtonText="{loc:Translate CancelButtonText}" Margin="0, 10, 0, 5"/>
<Grid Grid.Row="1">
<CollectionView ItemsSource="{Binding GroupedItems, Mode=OneWay}" VerticalScrollBarVisibility="Always" IsGrouped="True" Margin="0, 0, 0, 50">
<!-- Group Header Template: Titles of a Group -->
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="viewModels:GroupedSelectionItemList">
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
<Label FontSize="16" FontAttributes="Bold" Text="{Binding GroupName, StringFormat=' {0}'}" TextColor="{StaticResource Blue100Accent}" Margin="0, 25, 0, 0" />
<BoxView HeightRequest="0.5" Color="{StaticResource Gray200}" HorizontalOptions="FillAndExpand" Margin="0, 5, 0, 5" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<!-- Item Template: Selected Item -->
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="{x:Type databaseModels:ItemSelection}">
<Grid ColumnDefinitions="*, Auto" RowDefinitions="Auto" Padding="{OnPlatform Default='5, 0, 5, 0', iOS='5, 0, 5, 10'}">
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Item.Name}" VerticalOptions="Center" />
<Switch Grid.Row="0" Grid.Column="1" IsEnabled="True" IsToggled="{Binding IsSelected, Mode=TwoWay}" ThumbColor="{StaticResource Gray100}" OnColor="{StaticResource DarkOrange1}" VerticalOptions="Center" HorizontalOptions="Center" Margin="{OnPlatform Android='0, -5, 0, -5'}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</Grid>
Basically, changed the RowDefinitions
of the outer Grid
from <Grid RowDefinitions="Auto, *">
to <Grid RowDefinitions="Auto, Auto">
and also wrapped the CollectionView
inside another Grid
which did the job here for me.
/similarissues
Hi I'm an AI powered bot that finds similar issues based off the issue title.
Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!
Open similar issues:
- CollectionView with Grouping Generates UICollectionView "attempting to apply nil layout attributes to view" on iOS (#15862), similarity score: 0.86
- Using CollectionView IsGrouped="True" bound to ObservableCollection causes crash (#18481), similarity score: 0.80
- Grouped CollectionView content/items overlaps on iOS when data changes or when pull to refresh data (#20336), similarity score: 0.80
Closed similar issues:
- Error "NSInternalInconsistencyException Reason: Invalid update: invalid number of sections" in CollectionView on iOS still not closed (#16438), similarity score: 0.85
- UICollectionView is stuck in its update/layout loop (#12188), similarity score: 0.81
Note: You can give me feedback by thumbs upping or thumbs downing this comment.
I found the
NSInternalInconsistencyException
was occurring for me after theClear()
and when immediate adding back to the collection object. By adding a delay of 100ms here the crash went away.
Adding 100 ms doesn't resolve it for me. This issue existed in the XF and delay was the workaround we used which after porting to MAUI doesn't work anymore.
Hi, This is still an issue and we are restraining from publishing our App due to this.
None of the workarounds mentioned here & there worked for me.
Is there any ETA for this burning issue that restricting many from publishing their apps.
Regards
Just stumble upon this... seems to be many problems with grouped collectionview !
Running into the same bug.
For me it appears in a chat, with items that are not a fixed size, where I adjust the bottom margin of a CollectionView when the keyboard opens, which then results in the group headers being duplicated and all over the place.
Bildschirmaufnahme.2024-09-13.um.08.37.43.webm
Check out the repro here:
https://github.com/FlavioGoncalves-Cayas/CollectionViewDuplicateHeadersRepro
It's really frustrating to see that nobody cares. I just gave you a reproduction and there is no action taken whatsoever. We are encountering this problem in a production app and honestly it's embarassing.
Especially since there does not seem to be a viable workaround, or did I miss something?
Good news. This PR #24873 from @Tamilarasan-Paranthaman fixes the issue at least for my repro.