Bug 51754 - ListView context action problems after deleting item from ObservableCollection items source with CachingStrategy=RecycleElement
Summary: ListView context action problems after deleting item from ObservableCollectio...
Alias: None
Product: Forms
Classification: Xamarin
Component: iOS ()
Version: 2.3.4
Hardware: All All
: High normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2017-01-25 08:28 UTC by Roy Cornelissen
Modified: 2018-04-25 09:07 UTC (History)
7 users (show)

Tags: bug, ios, contextaction, listview, recycleelement, ac
Is this bug a regression?: ---
Last known good build:

Demo app with repro steps (70.26 KB, application/zip)
2017-01-25 08:28 UTC, Roy Cornelissen

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report for Bug 51754 on Developer Community or GitHub if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: Developer Community HTML or GitHub Markdown
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:

Description Roy Cornelissen 2017-01-25 08:28:36 UTC
Created attachment 19472 [details]
Demo app with repro steps

Using Xamarin.Forms Stable

We have been chasing a problem with the following situation with Xamarin.Forms ListView on iOS:

We have a ListView for which the ItemsSource is a ObservableRangeCollection (from James Montemagno's MvvmHelpers library). The ListView has a "Delete" ContextAction which does what you'd expect: delete the current row. We noticed (on iOS) that upon deleting the row, the row disappears from the ListView, however the Delete context action remains visible on the row that is now displayed in its place. CachingStrategy is set to RecycleElement. The problems do not occur when using RetainElement.

At first we thought there was a bug with the a cached ViewCell being reused and not properly reset, but we found out that the source of the problem was the way we were updating the underlying datasource.

Instead of just removing the item from the ObservableRangeCollection, we manipulated a List we kept in memory and then replaced the entire range with ObservableRangeCollection.ReplaceRange(). This triggers a CollectionChanged event with: NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset). The deleted row will be gone, but the state of the ViewCell remains and is now visible on the row what was directly below the row that was just deleted. When we changed this to do a Remove() of the item on the ObservableRangeCollection, a CollectionChanged event with NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove) is raised, and the ListView behaves as it should.

This happens only on iOS. On Android (using Long Press) the app crashes with a NullReferenceException when using DeleteWithReplaceRange (and CachingStrategy=RecycleElement):

at Xamarin.Forms.Platform.Android.CellAdapter.set_ContextView (Android.Views.View value) [0x00012] in C:\BuildAgent2\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\CellAdapter.cs:67 
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetView (System.Int32 position, Android.Views.View convertView, Android.Views.ViewGroup parent) [0x000e8] in C:\BuildAgent2\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:218 
  at Android.Widget.BaseAdapter.n_GetView_ILandroid_view_View_Landroid_view_ViewGroup_ (System.IntPtr jnienv, System.IntPtr native__this, System.Int32 position, System.IntPtr native_convertView, System.IntPtr native_parent) [0x0001a] in /Users/builder/data/lanes/4009/0ab90794/source/monodroid/src/Mono.Android/platforms/android-23/src/generated/Android.Widget.BaseAdapter.cs:443 
  at (wrapper dynamic-method) System.Object:97245d05-9ae7-4983-ae1d-26731c05f853 (intptr,intptr,int,intptr,intptr)


I've attached a sample app (based on the Xamarin "Working With ListView" sample) that demonstrates the behaviour. In the solution, open ContextActionsXaml.xaml.cs and alternate between the different implementations of the OnDelete method. Calling DeleteWithReplaceRange will show the "wrong" behaviour, calling DeleteWithRemove will show the behaviour we expect.

Start the application on both iOS and Android and delete one of the rows (not the last one) by revealing the context menu and pressing the red Delete button. When using DeleteWithReplaceRange, on iOS the row will disappear but the context menu remains open on the next row. On Android, the app will crash. When using DeleteWithRemove, the behaviour is as expected on iOS, but the app still crashes on Android.

In the Xaml, change the CachingStrategy to RetainElement and observe that the app works on both platforms (although the row animations on iOS are different between the implementations).
Comment 1 Jimmy [MSFT] 2017-03-15 18:09:33 UTC
I was able to reproduce this issue with the attached repro project and Forms on both iOS and Android. As described, on iOS the context menu would remain open at the same row index as the just removed item, and on Android the app would crash.

However, I also tested with Forms 2.3.4-pre5 and the issue appears to be partially resolved. With the newer version the Android app would no longer crash and it worked as expected, but on iOS the same issue still occurs. Therefore I am confirming this report so the team can investigate further.

# Version Tests

##Forms 2.3.4-pre5    
- iOS: BAD, context menu remains open 
- Android: GOOD

## Forms 
- iOS: BAD, context menu remains open 
- Android: BAD, crashes
Comment 2 Matthias 2017-04-05 15:12:03 UTC
We also encountered this issue with our ObservableCollection source when using the NotifyCollectionChangedAction.Reset action.

We found our ContextActions relating to the wrong elements (elements that were deleted before Reset was raised).

Setting the CachingStrategy to RetainElement resolves our issue too.

Reproduced on
- iOS: BAD
- Android: GOOD
Comment 3 David Ortinau [MSFT] 2017-06-15 03:22:52 UTC
This is still an issue in 2.3.5-pre3 and nightly. I'm reconfirming this issue and bumping up the priority.

I loaded up the iOS app, swipe to reveal the delete button, and deleted one of the middle rows. The row deleted and the table updated, but the context delete button remained. This does not happen when deleting the bottom row.
Comment 4 Fred 2018-04-25 09:07:41 UTC
I know this one is quite old but it seems it is happening (again?) with latest XF, at least on iOS.

Is there a status other than CONFIRMED?