From 2abf85e51dc6209c7e4be57d373830339f9ec138 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Mon, 1 Feb 2021 16:14:29 -0700 Subject: [PATCH] Signal layout request when CollectionView is in a layout Fixes #13551 --- .../Issue13203.cs | 3 +- .../Issue13551.cs | 136 ++++++++++++++++++ ...rin.Forms.Controls.Issues.Shared.projitems | 1 + .../CollectionView/ItemsViewController.cs | 1 + 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13551.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 index a2c1fa1b694..ddf41f83e2d 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13203.cs @@ -37,6 +37,7 @@ protected override void Init() var source = new List { new Item { Text = Success } }; cv.ItemsSource = source; + Content = cv; Appearing += (sender, args) => { cv.IsVisible = true; }; @@ -49,7 +50,7 @@ class Item #if UITEST [Test] - public void SettingGroupedCollectionViewItemSourceNullShouldNotCrash() + public void CollectionShouldInvalidateOnVisibilityChange() { RunningApp.WaitForElement(Success); } diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13551.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13551.cs new file mode 100644 index 00000000000..d5b05cb2a8b --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13551.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +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, 13551, "[Bug] [iOS] CollectionView does not display items if `IsVisible` modified via a binding/trigger", PlatformAffected.iOS)] +#if UITEST + [NUnit.Framework.Category(UITestCategories.CollectionView)] +#endif + public class Issue13551 : TestContentPage + { + const string Success1 = "Success1"; + const string Success2 = "Success2"; + + public ObservableCollection Source1 { get; } = new ObservableCollection(); + public ObservableCollection Source2 { get; } = new ObservableCollection(); + + CollectionView BindingWithConverter() + { + var cv = new CollectionView + { + IsVisible = true, + + ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding(nameof(Item.Text))); + return label; + }) + }; + + cv.SetBinding(CollectionView.ItemsSourceProperty, new Binding("Source1")); + cv.SetBinding(VisualElement.IsVisibleProperty, new Binding("Source1.Count", converter: new IntToBoolConverter())); + + return cv; + } + + CollectionView WithTrigger() + { + var cv = new CollectionView + { + IsVisible = true, + + ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding(nameof(Item.Text))); + return label; + }) + }; + + cv.SetBinding(CollectionView.ItemsSourceProperty, new Binding("Source2")); + + var trigger = new DataTrigger(typeof(CollectionView)); + trigger.Value = 0; + trigger.Setters.Add(new Setter() { Property = VisualElement.IsVisibleProperty, Value = false }); + trigger.Binding = new Binding("Source2.Count"); + + cv.Triggers.Add(trigger); + + return cv; + } + + protected override void Init() + { + BindingContext = this; + + var cv1 = BindingWithConverter(); + var cv2 = WithTrigger(); + + var grid = new Grid + { + RowDefinitions = new RowDefinitionCollection + { + new RowDefinition() { Height = GridLength.Star }, + new RowDefinition() { Height = GridLength.Star }, + } + }; + + grid.Children.Add(cv1); + grid.Children.Add(cv2); + Grid.SetRow(cv2, 1); + + Content = grid; + + Device.StartTimer(TimeSpan.FromMilliseconds(300), () => + { + Device.BeginInvokeOnMainThread(() => + { + Source1.Add(new Item { Text = Success1 }); + Source2.Add(new Item { Text = Success2 }); + }); + + return false; + }); + } + + class IntToBoolConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value is int val && val > 0; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } + + public class Item + { + public string Text { get; set; } + } + +#if UITEST + [Test] + public void CollectionInLayoutShouldInvalidateOnVisibilityChange() + { + RunningApp.WaitForElement(Success1); + RunningApp.WaitForElement(Success2); + } +#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 3a9a2356a5e..c6c4c50679c 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 @@ -12,6 +12,7 @@ + diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs b/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs index 6222bdcecb8..2b97afb6f00 100644 --- a/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs +++ b/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs @@ -610,6 +610,7 @@ void ItemsViewPropertyChanged(object sender, PropertyChangedEventArgs changedPro if (ItemsView.IsVisible) { Layout.InvalidateLayout(); + CollectionView.LayoutIfNeeded(); } } }