Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 91519

Forms.ListView crashes when ItemSource has item removed and another inserted

$
0
0

I am at my whits end - any help would be greatly appreciated. I have a PCL Xamarin.Forms app on iOS and Android. The app runs great on Android but crashes on iOS. To best illustrate the issue, I have included a simplified program (below).

PLEASE NOTE: Crash in second comment (below) is identical to the one I am getting in my full featured application. Please consider it the crash in question.

Description of the program:
- Single view, PCL, iOS and Android
- View is a ListView
- ListView's ItemsSource is a List of at least two Observable Collections (of an object w/ BindableProperties)
- ListView's Grouping is enabled
- ListView uses a dynamic ViewCell as DataTemplate

Environment:
- iOS 8.x and 9.x (device or simulator)
- Xamarin.Forms 1.5.1.6468 (see second comment, below for behavior on 1.5.1.6471)

Actions:
- start program on device or simulator
- make first selection (select a cell in the first group, cell will display the word "pizza")
- make second selection (again, from the first group)

Expected behavior: App will show original contents of first selection at the location of the second selection

Observed behavior: App crashes with the following stack trace: (see second comment, below for different stack trace on 1.5.1.6471)

System.NullReferenceException: Object reference not set to an instance of an object
  at Xamarin.Forms.Platform.iOS.ViewCellRenderer+ViewTableCell.UpdateCell (Xamarin.Forms.ViewCell cell) [0x000f4] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.ViewCellRenderer+ViewTableCell.set_ViewCell (Xamarin.Forms.ViewCell value) [0x0000a] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.ViewCellRenderer.GetCell (Xamarin.Forms.Cell item, UIKit.UITableViewCell reusableCell, UIKit.UITableView tv) [0x0004d] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.CellTableViewCell.GetNativeCell (UIKit.UITableView tableView, Xamarin.Forms.Cell cell) [0x0007e] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.ListViewRenderer+ListViewDataSource.GetCell (UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) [0x00008] in <filename unknown>:0
  at at (wrapper managed-to-native) ObjCRuntime.Messaging:void_objc_msgSend (intptr,intptr)
  at UIKit.UITableView.EndUpdates () [0x00010] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/src/build/ios/native/UIKit/UITableView.g.cs:297
  at Xamarin.Forms.Platform.iOS.ListViewRenderer.UpdateItems (System.Collections.Specialized.NotifyCollectionChangedEventArgs e, Int32 section, Boolean resetWhenGrouped) [0x000ef] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.ListViewRenderer.OnGroupedCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0001e] in <filename unknown>:0
  at Xamarin.Forms.TemplatedItemsList`2[Xamarin.Forms.ItemsView`1[Xamarin.Forms.Cell],Xamarin.Forms.Cell].OnInnerCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000a] in <filename unknown>:0
  at Xamarin.Forms.TemplatedItemsList`2[Xamarin.Forms.ItemsView`1[Xamarin.Forms.Cell],Xamarin.Forms.Cell].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000a] in <filename unknown>:0
  at Xamarin.Forms.TemplatedItemsList`2[Xamarin.Forms.ItemsView`1[Xamarin.Forms.Cell],Xamarin.Forms.Cell].OnProxyCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e, Boolean fixWindows) [0x004fb] in <filename unknown>:0
  at Xamarin.Forms.TemplatedItemsList`2[Xamarin.Forms.ItemsView`1[Xamarin.Forms.Cell],Xamarin.Forms.Cell].OnProxyCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00000] in <filename unknown>:0
  at Xamarin.Forms.ListProxy.OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000a] in <filename unknown>:0
  at Xamarin.Forms.ListProxy+<>c__DisplayClassc.<OnCollectionChanged>b__8 () [0x00013] in <filename unknown>:0
  at Xamarin.Forms.ListProxy.OnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x000ae] in <filename unknown>:0
  at Xamarin.Forms.ListProxy+WeakNotifyProxy.OnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00031] in <filename unknown>:0
  at System.Collections.ObjectModel.ObservableCollection`1[ColorGroupList.App+Item].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00012] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:286
  at System.Collections.ObjectModel.ObservableCollection`1[ColorGroupList.App+Item].OnCollectionChanged (NotifyCollectionChangedAction action, System.Object item, Int32 index) [0x00000] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:349
  at System.Collections.ObjectModel.ObservableCollection`1[ColorGroupList.App+Item].RemoveItem (Int32 index) [0x0002b] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:203
  at System.Collections.ObjectModel.Collection`1[ColorGroupList.App+Item].Remove (ColorGroupList.Item item) [0x0002d] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/collections/objectmodel/collection.cs:134
  at ColorGroupList.App.OnItemSelected (System.Object sender, Xamarin.Forms.SelectedItemChangedEventArgs e) [0x0004e] in /Users/ben/Downloads/xamarin-forms-book-preview-2-master/Chapter19/ColorGroupList/ColorGroupList/ColorGroupList/App.cs:71
  at at (wrapper delegate-invoke) System.EventHandler`1<Xamarin.Forms.SelectedItemChangedEventArgs>:invoke_void_object_TEventArgs (object,Xamarin.Forms.SelectedItemChangedEventArgs)
  at Xamarin.Forms.ListView.OnSelectedItemChanged (Xamarin.Forms.BindableObject bindable, System.Object oldValue, System.Object newValue) [0x0001c] in <filename unknown>:0
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindablePropertyContext context, System.Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent) [0x00112] in <filename unknown>:0
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes) [0x00235] in <filename unknown>:0
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, SetValueFlags attributes) [0x00000] in <filename unknown>:0
  at Xamarin.Forms.ListView.NotifyRowTapped (Int32 groupIndex, Int32 inGroupIndex) [0x00048] in <filename unknown>:0
  at Xamarin.Forms.Platform.iOS.ListViewRenderer+ListViewDataSource.RowSelected (UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) [0x00041] in <filename unknown>:0
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/src/UIKit/UIApplication.cs:77
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/2320/1f068b49/source/maccore/src/UIKit/UIApplication.cs:61
  at ColorGroupList.iOS.Application.Main (System.String[] args) [0x00008] in /Users/ben/Downloads/xamarin-forms-book-preview-2-master/Chapter19/ColorGroupList/ColorGroupList/ColorGroupList.iOS/Main.cs:17

Code:

using System;
using Xamarin.Forms;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace ColorGroupList
{
    public class App : Application
    {
        public class Item : BindableObject {
        }

        public class Item<T> : Item {
            public static BindableProperty ValueProperty = BindableProperty.Create ("Value", typeof(T), typeof(Item<T>), default(T));
            public T Value {
                get { return (T)GetValue (ValueProperty); }
                set { SetValue (ValueProperty, value); }
            }
        }

        public class ItemGroup : ObservableCollection<Item> {
            public string Title;
        }

        List<ItemGroup> groups;
        ItemGroup strings, booleans;
        ListView listView;

        public App()
        {
            groups = new List<ItemGroup> ();

            strings = new ItemGroup () { Title = "Strings" };
            for (int i = 0; i < 10; i++)
                strings.Add (new Item<string> () { Value = "strings[" + i + "]"} );
            groups.Add (strings); 


            booleans = new ItemGroup () { Title = "Booleans" };
            for (int i = 0; i < 10; i++)
                booleans.Add (new Item<bool> () { Value = i%2==1 });
            groups.Add (booleans);

            listView = new ListView () {
                ItemsSource = groups,
                ItemTemplate = new DataTemplate (typeof(DynamicCell)),
                IsGroupingEnabled = true,
                HasUnevenRows = true,
            };
            listView.ItemSelected += OnItemSelected;

            MainPage = new ContentPage () {
                Content = listView,
                Padding = new Thickness(0,20,0,0),
            };
        }

        Item lastItem = new Item<string>() { Value = "pizza" };
        public void OnItemSelected(object sender, SelectedItemChangedEventArgs e) {
            listView.SelectedItem = null;
            var item = e.SelectedItem as Item;
            foreach (ItemGroup group in groups) {
                if (group.Contains (item)) {
                    int index = group.IndexOf (item);
                    var tmpItem = item;
                    group.Remove (item);
                    group.Insert (index, lastItem);
                    System.Diagnostics.Debug.WriteLine ("removed:" + item + " for:" + lastItem);
                    lastItem = tmpItem;
                    return;
                }
            }
        }

        public class HeaderCell : ViewCell {
            public HeaderCell() {
                View = new Label { TextColor = Color.White, BackgroundColor = Color.Blue, HeightRequest=25 };
            }
            protected override void OnBindingContextChanged() {
                base.OnBindingContextChanged ();
                ((Label)View).Text = ((ItemGroup)BindingContext).Title;
            }
        }

        public class DynamicCell : ViewCell {
            protected override void OnBindingContextChanged() {
                base.OnBindingContextChanged ();

                Type type = BindingContext.GetType ();
                if (type == typeof(Item))
                    View = new BoxView () { BackgroundColor = Color.Gray };
                else if (type == typeof(Item<string>)) {
                    View = new Label ();
                    View.BindingContext = BindingContext;
                    View.SetBinding (Label.TextProperty, "Value");
                } else if (type==typeof(Item<bool>)) {
                    View = new Switch ();
                    View.BindingContext = BindingContext;
                    View.SetBinding (Switch.IsToggledProperty, "Value");
                }
                View.HeightRequest = 56;
            }
        }
    }
}

Special notes:
- Does not crash on Android
- If only one view group is shown, the app does not crash
- If the dynamic behavior of DynamicCell is removed (see below), the app does not crash

public class DynamicCell : ViewCell {
            protected override void OnBindingContextChanged() {
                base.OnBindingContextChanged ();
                View = new Label ();
                View.BindingContext = BindingContext;
                View.SetBinding (Label.TextProperty, "Value");
            }
        }

Viewing all articles
Browse latest Browse all 91519

Trending Articles