From c419953e86aa4de9a680439564abe69d60331ab5 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Fri, 15 Jan 2021 03:56:59 -0700 Subject: [PATCH] Invalidate CollectionView Layout on transition to IsVisible = true (#13370) fixes #13203 * Automated test * Tell CollectionView Layout to invalidate if IsVisible transitions to true; fixes #13203 * Remove old waitforelement call * Unsubscribe property changed handler during Dispose --- .../Issue13203.cs | 59 +++++++++++++++++++ ...rin.Forms.Controls.Issues.Shared.projitems | 1 + .../CollectionView/ItemsViewController.cs | 16 +++++ 3 files changed, 76 insertions(+) create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs new file mode 100644 index 00000000000..a2c1fa1b694 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +#if UITEST +using Xamarin.UITest; +using NUnit.Framework; +using Xamarin.Forms.Core.UITests; +#endif + +namespace Xamarin.Forms.Controls.Issues +{ + [Issue(IssueTracker.Github, 13203, "[Bug] [iOS] CollectionView does not bind to items if `IsVisible=False`", PlatformAffected.iOS)] +#if UITEST + [NUnit.Framework.Category(UITestCategories.CollectionView)] +#endif + public class Issue13203 : TestContentPage + { + const string Success = "Success"; + + protected override void Init() + { + var cv = new CollectionView + { + IsVisible = false, + + ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding(nameof(Item.Text))); + return label; + }) + }; + + var source = new List { new Item { Text = Success } }; + cv.ItemsSource = source; + Content = cv; + + Appearing += (sender, args) => { cv.IsVisible = true; }; + } + + class Item + { + public string Text { get; set; } + } + +#if UITEST + [Test] + public void SettingGroupedCollectionViewItemSourceNullShouldNotCrash() + { + RunningApp.WaitForElement(Success); + } +#endif + } +} + diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index d345c75c87a..3e720123bd0 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -38,6 +38,7 @@ + diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs b/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs index 96d28bfb37f..2c42e89a917 100644 --- a/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs +++ b/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using CoreGraphics; using Foundation; using UIKit; @@ -27,6 +28,8 @@ protected ItemsViewController(TItemsView itemsView, ItemsViewLayout layout) : ba { ItemsView = itemsView; ItemsViewLayout = layout; + + ItemsView.PropertyChanged += ItemsViewPropertyChanged; } public void UpdateLayout(ItemsViewLayout newLayout) @@ -56,6 +59,8 @@ protected override void Dispose(bool disposing) if (disposing) { + ItemsView.PropertyChanged -= ItemsViewPropertyChanged; + ItemsSource?.Dispose(); CollectionView.Delegate = null; Delegator?.Dispose(); @@ -457,5 +462,16 @@ public TemplatedCell CreateMeasurementCell(NSIndexPath indexPath) return templatedCell; } + + void ItemsViewPropertyChanged(object sender, PropertyChangedEventArgs changedProperty) + { + if (changedProperty.Is(VisualElement.IsVisibleProperty)) + { + if (ItemsView.IsVisible) + { + Layout.InvalidateLayout(); + } + } + } } }