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");
}
}