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

[iOS] Allow observable source update while CollectionView is not visible #13678

Merged
merged 3 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
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, 13126, "[Bug] Regression: 5.0.0-pre5 often fails to draw dynamically loaded collection view content", PlatformAffected.iOS)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.CollectionView)]
#endif
public class Issue13126 : TestContentPage
{
_13126VM _vm;
const string Success = "Success";

protected override void Init()
{
var collectionView = BindingWithConverter();

var grid = new Grid
{
RowDefinitions = new RowDefinitionCollection
{
new RowDefinition() { Height = GridLength.Star },
}
};

grid.Children.Add(collectionView);

Content = grid;

_vm = new _13126VM();
BindingContext = _vm;
}

protected async override void OnParentSet()
{
base.OnParentSet();
_vm.IsBusy = true;

await Task.Delay(1000);

_vm.Data.Add(Success);

_vm.IsBusy = false;
}

internal static CollectionView BindingWithConverter()
{
var cv = new CollectionView
{
IsVisible = true,

ItemTemplate = new DataTemplate(() =>
{
var label = new Label();
label.SetBinding(Label.TextProperty, new Binding("."));
return label;
})
};

cv.EmptyView = new Label { Text = "Should not see me" };

cv.SetBinding(CollectionView.ItemsSourceProperty, new Binding("Data"));
cv.SetBinding(VisualElement.IsVisibleProperty, new Binding("IsBusy", converter: new BoolInverter()));

return cv;
}

class BoolInverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !((bool)value);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

internal class _13126VM : INotifyPropertyChanged
{
private bool _isBusy;

public bool IsBusy
{
get
{
return _isBusy;
}

set
{
_isBusy = value;
OnPropertyChanged(nameof(IsBusy));
}
}

public OptimizedObservableCollection<string> Data { get; } = new OptimizedObservableCollection<string>();

public event PropertyChangedEventHandler PropertyChanged;

void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}

internal class OptimizedObservableCollection<T> : ObservableCollection<T>
{
bool _shouldRaiseNotifications = true;

public OptimizedObservableCollection()
{
}

public OptimizedObservableCollection(IEnumerable<T> collection)
: base(collection)
{
}

public IDisposable BeginMassUpdate()
{
return new MassUpdater(this);
}

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (_shouldRaiseNotifications)
base.OnCollectionChanged(e);
}

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (_shouldRaiseNotifications)
base.OnPropertyChanged(e);
}

class MassUpdater : IDisposable
{
readonly OptimizedObservableCollection<T> parent;
public MassUpdater(OptimizedObservableCollection<T> parent)
{
this.parent = parent;
parent._shouldRaiseNotifications = false;
}

public void Dispose()
{
parent._shouldRaiseNotifications = true;
parent.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
parent.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
parent.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
}

#if UITEST
[Test]
public void CollectionViewShouldSourceShouldUpdateWhileInvisible()
{
RunningApp.WaitForElement(Success);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using static Xamarin.Forms.Controls.Issues.Issue13126;

#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Issue(IssueTracker.Github, 13126, "[Bug] Regression: 5.0.0-pre5 often fails to draw dynamically loaded collection view content",
PlatformAffected.iOS, issueTestNumber:1)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.CollectionView)]
#endif
public class Issue13126_2 : TestContentPage
{
_13126VM _vm;
const string Success = "Success";

protected override void Init()
{
var collectionView = BindingWithConverter();

var grid = new Grid
{
RowDefinitions = new RowDefinitionCollection
{
new RowDefinition() { Height = GridLength.Star },
}
};

grid.Children.Add(collectionView);

Content = grid;

_vm = new _13126VM();
BindingContext = _vm;
}

protected async override void OnParentSet()
{
base.OnParentSet();
_vm.IsBusy = true;

await Task.Delay(1000);

using (_vm.Data.BeginMassUpdate())
{
_vm.Data.Add(Success);
}

_vm.IsBusy = false;
}

#if UITEST
[Test]
public void CollectionViewShouldSourceShouldResetWhileInvisible()
{
RunningApp.WaitForElement(Success);
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11214.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13109.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13126.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13126_2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13551.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RadioButtonTemplateFromStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellWithCustomRendererDisabledAnimations.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,18 @@ void UpdateVisualStates()

_oldViews = newViews;
}

protected internal override void UpdateVisibility()
{
if (ItemsView.IsVisible)
{
CollectionView.Hidden = false;
}
else
{
CollectionView.Hidden = true;
}
}
}

class CarouselViewLoopManager : IDisposable
Expand Down