[Bug][iOS] listview / observable collection throwing native error on load (#6576)
authorGerald Versluis <gerald.versluis@microsoft.com>
Thu, 18 Jul 2019 02:49:21 +0000 (04:49 +0200)
committerSamantha Houts <samhouts@users.noreply.github.com>
Thu, 18 Jul 2019 02:49:21 +0000 (19:49 -0700)
* Added reproduction and commented out the misbehaving code

* Fixed merge conflicts

# Conflicts:
# Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

* Implemented UI test

* Somehow merged in a non-existing UI test

* Removed DetermineEstimatedRowHeight in WillDisplay

* Revert "Removed DetermineEstimatedRowHeight in WillDisplay"

This reverts commit 431178d923c3bf642aae83331a5dc5b57c4436de.

* Removed WillDisplay with DetermineEstimatedRowHeight

* Reinstate projitems

* Added some more test scenarios

* Removed commented code

* Update Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6472.cs
fixes #6472

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6472.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6472.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6472.cs
new file mode 100644 (file)
index 0000000..cce5fb9
--- /dev/null
@@ -0,0 +1,179 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+       [Category(UITestCategories.ManualReview)]
+#endif
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 6472, "[Bug][iOS] listview / observable collection throwing native error on load", PlatformAffected.iOS)]
+       public class Issue6472 : TestContentPage
+       {
+               const string ListViewAutomationId = "TheListview";
+               const string ClearButtonAutomationId = "ClearButton";
+               const string UiThreadButtonAutomationId = "UiThreadButton";
+               const string OtherThreadButtonAutomationId = "OtherThreadButton";
+               const string AddItemsAddRangeButtonAutomationId = "AddItemsAddRangeButton";
+
+               class testData
+               {
+                       public int recordId { get; set; }
+                       public string recordText { get; set; }
+               }
+
+               static class staticData
+               {
+                       public static ObservableCollection<testData> TestCollection = new ObservableCollection<testData>();
+                       public async static void testPopulate()
+                       {
+                               await Task.Run(() =>
+                               {
+                                       TestCollection.Clear();
+                                       for (int i = 0; i < 11; i++)
+                                       {
+                                               var tdn = new testData
+                                               {
+                                                       recordId = i,
+                                                       recordText = i.ToString()
+                                               };
+                                               TestCollection.Add(tdn);
+                                       }
+                               });
+                       }
+               }
+
+               protected override void Init()
+               {
+                       var clearButton = new Button
+                       {
+                               Text = "Clear collection",
+                               AutomationId = ClearButtonAutomationId
+                       };
+
+                       clearButton.Clicked += (s, a) =>
+                       {
+                               staticData.TestCollection.Clear();
+                       };
+
+                       var buttonAddElementUiThreadButton = new Button
+                       {
+                               Text = "Add item from UI thread",
+                               AutomationId = UiThreadButtonAutomationId
+                       };
+
+                       buttonAddElementUiThreadButton.Clicked += (s, a) =>
+                       {
+                               staticData.TestCollection.Add(new testData
+                               {
+                                       recordId = 1,
+                                       recordText = "Just one"
+                               });
+
+                               staticData.TestCollection.Add(new testData
+                               {
+                                       recordId = 2,
+                                       recordText = "Just two"
+                               });
+
+                               staticData.TestCollection.Add(new testData
+                               {
+                                       recordId = 3,
+                                       recordText = "Just three"
+                               });
+                       };
+
+                       var buttonAddElementOtherThreadButton = new Button
+                       {
+                               Text = "Add item from other thread",
+                               AutomationId = OtherThreadButtonAutomationId
+                       };
+
+                       buttonAddElementOtherThreadButton.Clicked += (s, a) =>
+                       {
+                               Task.Run(() =>
+                               {
+                                       staticData.TestCollection.Add(new testData
+                                       {
+                                               recordId = 42,
+                                               recordText = "THE answer"
+                                       });
+
+                                       staticData.TestCollection.Add(new testData
+                                       {
+                                               recordId = 1337,
+                                               recordText = "1337 HaxX0r"
+                                       });
+                               });
+                       };
+
+                       var listView = new ListView
+                       {
+                               ItemTemplate = new DataTemplate(() =>
+                               {
+                                       var labelAccount = new Label
+                                       {
+                                               Margin = new Thickness(10, 0),
+                                               VerticalTextAlignment = TextAlignment.Center,
+                                               HorizontalTextAlignment = TextAlignment.Start,
+                                               LineBreakMode = LineBreakMode.NoWrap,
+                                       };
+                                       labelAccount.FontSize = 18;
+                                       labelAccount.SetBinding(Label.TextProperty, "recordText");
+
+                                       var stackAccountLayout = new StackLayout
+                                       {
+                                               Orientation = StackOrientation.Vertical,
+                                               VerticalOptions = LayoutOptions.Center,
+                                               HorizontalOptions = LayoutOptions.StartAndExpand,
+                                               Children = { labelAccount }
+                                       };
+                                       return new ViewCell { View = stackAccountLayout };
+                               }),
+                               AutomationId = ListViewAutomationId
+                       };
+
+                       var stack = new StackLayout();
+                       stack.Children.Add(buttonAddElementOtherThreadButton);
+                       stack.Children.Add(buttonAddElementUiThreadButton);
+                       stack.Children.Add(clearButton);
+                       stack.Children.Add(listView);
+
+
+                       Content = stack;
+                       listView.ItemsSource = staticData.TestCollection;
+               }
+
+               protected override void OnAppearing()
+               {
+                       base.OnAppearing();
+                       staticData.testPopulate();
+               }
+
+#if UITEST && __IOS__
+               [Test]
+               public void ListViewDoesNotThrowExceptionWithObservableCollection() 
+               {
+                       RunningApp.WaitForElement (ListViewAutomationId);
+                       RunningApp.Screenshot ("We got here without an exception while loading the data and data is visible");
+
+                       RunningApp.Tap(ClearButtonAutomationId);
+                       RunningApp.Tap(UiThreadButtonAutomationId);
+                       RunningApp.Tap(OtherThreadButtonAutomationId);
+
+                       RunningApp.Tap(ClearButtonAutomationId);
+                       RunningApp.Tap(OtherThreadButtonAutomationId);
+                       RunningApp.Tap(UiThreadButtonAutomationId);
+
+               }
+#endif
+       }
+}
index 2b4a008..9e53e7d 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Issue5888.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue6334.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue6368.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue6472.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue6614.cs" />
   </ItemGroup>
   <ItemGroup>
index 613af35..fbd23fd 100644 (file)
@@ -1173,15 +1173,6 @@ namespace Xamarin.Forms.Platform.iOS
                                List.NotifyRowTapped(indexPath.Section, indexPath.Row, formsCell);
                        }
 
-                       public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
-                       {
-                               if (!_estimatedRowHeight)
-                               {
-                                       // Our cell size/estimate is out of date, probably because we moved from zero to one item; update it
-                                       DetermineEstimatedRowHeight();
-                               }
-                       }
-
                        public override nint RowsInSection(UITableView tableview, nint section)
                        {
                                int countOverride;
@@ -1373,7 +1364,6 @@ namespace Xamarin.Forms.Platform.iOS
 
                        protected virtual void UpdateEstimatedRowHeight(UITableView tableView)
                        {
-
                                // We need to set a default estimated row height,
                                // because re-setting it later(when we have items on the TIL)
                                // will cause the UITableView to reload, and throw an Exception