Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit a10c2c6

Browse files
authored
[iOS] Allow observable source update while CollectionView is not visible (#13678) fixes #13126
* Allow item source updates while CollectionView is hidden; prevent CollectionView updates while CollectionView is hidden; fixes #13126 * Fix bug where measurement cell content is applied to the wrong cell Only force layout on transition from invisible to visible Move cell size cache to layout and clear cache on size change (e.g., rotation) Use ItemsView size for constraints when possible; * Add test for Reset situation; fix bug with Reset before CollectionView is visible;
1 parent 7ea5159 commit a10c2c6

File tree

9 files changed

+377
-60
lines changed

9 files changed

+377
-60
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Collections.Specialized;
5+
using System.ComponentModel;
6+
using System.Globalization;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Xamarin.Forms.CustomAttributes;
10+
using Xamarin.Forms.Internals;
11+
12+
#if UITEST
13+
using Xamarin.UITest;
14+
using NUnit.Framework;
15+
using Xamarin.Forms.Core.UITests;
16+
#endif
17+
18+
namespace Xamarin.Forms.Controls.Issues
19+
{
20+
[Issue(IssueTracker.Github, 13126, "[Bug] Regression: 5.0.0-pre5 often fails to draw dynamically loaded collection view content", PlatformAffected.iOS)]
21+
#if UITEST
22+
[NUnit.Framework.Category(UITestCategories.CollectionView)]
23+
#endif
24+
public class Issue13126 : TestContentPage
25+
{
26+
_13126VM _vm;
27+
const string Success = "Success";
28+
29+
protected override void Init()
30+
{
31+
var collectionView = BindingWithConverter();
32+
33+
var grid = new Grid
34+
{
35+
RowDefinitions = new RowDefinitionCollection
36+
{
37+
new RowDefinition() { Height = GridLength.Star },
38+
}
39+
};
40+
41+
grid.Children.Add(collectionView);
42+
43+
Content = grid;
44+
45+
_vm = new _13126VM();
46+
BindingContext = _vm;
47+
}
48+
49+
protected async override void OnParentSet()
50+
{
51+
base.OnParentSet();
52+
_vm.IsBusy = true;
53+
54+
await Task.Delay(1000);
55+
56+
_vm.Data.Add(Success);
57+
58+
_vm.IsBusy = false;
59+
}
60+
61+
internal static CollectionView BindingWithConverter()
62+
{
63+
var cv = new CollectionView
64+
{
65+
IsVisible = true,
66+
67+
ItemTemplate = new DataTemplate(() =>
68+
{
69+
var label = new Label();
70+
label.SetBinding(Label.TextProperty, new Binding("."));
71+
return label;
72+
})
73+
};
74+
75+
cv.EmptyView = new Label { Text = "Should not see me" };
76+
77+
cv.SetBinding(CollectionView.ItemsSourceProperty, new Binding("Data"));
78+
cv.SetBinding(VisualElement.IsVisibleProperty, new Binding("IsBusy", converter: new BoolInverter()));
79+
80+
return cv;
81+
}
82+
83+
class BoolInverter : IValueConverter
84+
{
85+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
86+
{
87+
return !((bool)value);
88+
}
89+
90+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
91+
{
92+
throw new NotImplementedException();
93+
}
94+
}
95+
96+
internal class _13126VM : INotifyPropertyChanged
97+
{
98+
private bool _isBusy;
99+
100+
public bool IsBusy
101+
{
102+
get
103+
{
104+
return _isBusy;
105+
}
106+
107+
set
108+
{
109+
_isBusy = value;
110+
OnPropertyChanged(nameof(IsBusy));
111+
}
112+
}
113+
114+
public OptimizedObservableCollection<string> Data { get; } = new OptimizedObservableCollection<string>();
115+
116+
public event PropertyChangedEventHandler PropertyChanged;
117+
118+
void OnPropertyChanged(string name)
119+
{
120+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
121+
}
122+
}
123+
124+
internal class OptimizedObservableCollection<T> : ObservableCollection<T>
125+
{
126+
bool _shouldRaiseNotifications = true;
127+
128+
public OptimizedObservableCollection()
129+
{
130+
}
131+
132+
public OptimizedObservableCollection(IEnumerable<T> collection)
133+
: base(collection)
134+
{
135+
}
136+
137+
public IDisposable BeginMassUpdate()
138+
{
139+
return new MassUpdater(this);
140+
}
141+
142+
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
143+
{
144+
if (_shouldRaiseNotifications)
145+
base.OnCollectionChanged(e);
146+
}
147+
148+
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
149+
{
150+
if (_shouldRaiseNotifications)
151+
base.OnPropertyChanged(e);
152+
}
153+
154+
class MassUpdater : IDisposable
155+
{
156+
readonly OptimizedObservableCollection<T> parent;
157+
public MassUpdater(OptimizedObservableCollection<T> parent)
158+
{
159+
this.parent = parent;
160+
parent._shouldRaiseNotifications = false;
161+
}
162+
163+
public void Dispose()
164+
{
165+
parent._shouldRaiseNotifications = true;
166+
parent.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
167+
parent.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
168+
parent.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
169+
}
170+
}
171+
}
172+
173+
#if UITEST
174+
[Test]
175+
public void CollectionViewShouldSourceShouldUpdateWhileInvisible()
176+
{
177+
RunningApp.WaitForElement(Success);
178+
}
179+
#endif
180+
}
181+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Collections.Specialized;
5+
using System.ComponentModel;
6+
using System.Globalization;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Xamarin.Forms.CustomAttributes;
10+
using Xamarin.Forms.Internals;
11+
using static Xamarin.Forms.Controls.Issues.Issue13126;
12+
13+
#if UITEST
14+
using Xamarin.UITest;
15+
using NUnit.Framework;
16+
using Xamarin.Forms.Core.UITests;
17+
#endif
18+
19+
namespace Xamarin.Forms.Controls.Issues
20+
{
21+
[Issue(IssueTracker.Github, 13126, "[Bug] Regression: 5.0.0-pre5 often fails to draw dynamically loaded collection view content",
22+
PlatformAffected.iOS, issueTestNumber:1)]
23+
#if UITEST
24+
[NUnit.Framework.Category(UITestCategories.CollectionView)]
25+
#endif
26+
public class Issue13126_2 : TestContentPage
27+
{
28+
_13126VM _vm;
29+
const string Success = "Success";
30+
31+
protected override void Init()
32+
{
33+
var collectionView = BindingWithConverter();
34+
35+
var grid = new Grid
36+
{
37+
RowDefinitions = new RowDefinitionCollection
38+
{
39+
new RowDefinition() { Height = GridLength.Star },
40+
}
41+
};
42+
43+
grid.Children.Add(collectionView);
44+
45+
Content = grid;
46+
47+
_vm = new _13126VM();
48+
BindingContext = _vm;
49+
}
50+
51+
protected async override void OnParentSet()
52+
{
53+
base.OnParentSet();
54+
_vm.IsBusy = true;
55+
56+
await Task.Delay(1000);
57+
58+
using (_vm.Data.BeginMassUpdate())
59+
{
60+
_vm.Data.Add(Success);
61+
}
62+
63+
_vm.IsBusy = false;
64+
}
65+
66+
#if UITEST
67+
[Test]
68+
public void CollectionViewShouldSourceShouldResetWhileInvisible()
69+
{
70+
RunningApp.WaitForElement(Success);
71+
}
72+
#endif
73+
}
74+
}

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
1313
<Compile Include="$(MSBuildThisFileDirectory)Issue11214.cs" />
1414
<Compile Include="$(MSBuildThisFileDirectory)Issue13109.cs" />
15+
<Compile Include="$(MSBuildThisFileDirectory)Issue13126.cs" />
16+
<Compile Include="$(MSBuildThisFileDirectory)Issue13126_2.cs" />
1517
<Compile Include="$(MSBuildThisFileDirectory)Issue13551.cs" />
1618
<Compile Include="$(MSBuildThisFileDirectory)RadioButtonTemplateFromStyle.cs" />
1719
<Compile Include="$(MSBuildThisFileDirectory)ShellWithCustomRendererDisabledAnimations.cs" />

Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewController.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,18 @@ void UpdateVisualStates()
469469

470470
_oldViews = newViews;
471471
}
472+
473+
protected internal override void UpdateVisibility()
474+
{
475+
if (ItemsView.IsVisible)
476+
{
477+
CollectionView.Hidden = false;
478+
}
479+
else
480+
{
481+
CollectionView.Hidden = true;
482+
}
483+
}
472484
}
473485

474486
class CarouselViewLoopManager : IDisposable

0 commit comments

Comments
 (0)