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

Commit

Permalink
Allow item source updates while CollectionView is hidden; prevent
Browse files Browse the repository at this point in the history
CollectionView updates while CollectionView is hidden;
fixes #13126
  • Loading branch information
hartez committed Feb 5, 2021
1 parent 3d054b8 commit ac9dde6
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Xamarin.Forms.CustomAttributes;

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)]

public class Issue13126 : TestContentPage
{
_13126VM _vm;
const string Success1 = "Success1";

protected override void Init()
{
_vm = new _13126VM();
BindingContext = _vm;

var cv1 = BindingWithConverter();

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

grid.Children.Add(cv1);

Content = grid;

_vm.IsBusy = true;

Device.StartTimer(TimeSpan.FromMilliseconds(300), () =>
{
Device.BeginInvokeOnMainThread(() =>
{
_vm.Data.Add(Success1);
_vm.IsBusy = false;
});
return false;
});
}

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

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

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();
}
}
}

class _13126VM : INotifyPropertyChanged
{
private bool _isBusy;

public bool IsBusy
{
get
{
return _isBusy;
}

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

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

public event PropertyChangedEventHandler PropertyChanged;

void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11214.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13109.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13126.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13551.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RadioButtonTemplateFromStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellWithCustomRendererDisabledAnimations.cs" />
Expand Down
36 changes: 17 additions & 19 deletions Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ protected ItemsViewController(TItemsView itemsView, ItemsViewLayout layout) : ba
{
ItemsView = itemsView;
ItemsViewLayout = layout;

ItemsView.PropertyChanged += ItemsViewPropertyChanged;
}

public void UpdateLayout(ItemsViewLayout newLayout)
Expand Down Expand Up @@ -62,8 +60,6 @@ protected override void Dispose(bool disposing)

if (disposing)
{
ItemsView.PropertyChanged -= ItemsViewPropertyChanged;

ItemsSource?.Dispose();

CollectionView.Delegate = null;
Expand Down Expand Up @@ -100,10 +96,10 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS

public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
if (!_initialized)
{
return 0;
}
//if (!_initialized)
//{
// return 0;
//}

CheckForEmptySource();

Expand Down Expand Up @@ -225,10 +221,10 @@ public virtual void UpdateFlowDirection()

public override nint NumberOfSections(UICollectionView collectionView)
{
if(!_initialized)
{
return 0;
}
//if(!_initialized)
//{
// return 0;
//}

CheckForEmptySource();
return ItemsSource.GroupCount;
Expand Down Expand Up @@ -610,15 +606,17 @@ internal CGSize GetSizeForItem(NSIndexPath indexPath)
return ItemsViewLayout.EstimatedItemSize;
}

void ItemsViewPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
internal void UpdateVisibility()
{
if (changedProperty.Is(VisualElement.IsVisibleProperty))
if (ItemsView.IsVisible)
{
if (ItemsView.IsVisible)
{
Layout.InvalidateLayout();
CollectionView.LayoutIfNeeded();
}
CollectionView.Hidden = false;
Layout.InvalidateLayout();
CollectionView.LayoutIfNeeded();
}
else
{
CollectionView.Hidden = true;
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
{
UpdateFlowDirection();
}
else if (changedProperty.Is(VisualElement.IsVisibleProperty))
{
UpdateVisibility();
}
}

protected abstract ItemsViewLayout SelectLayout();
Expand Down Expand Up @@ -101,6 +105,7 @@ protected virtual void SetUpNewElement(TItemsView newElement)
UpdateVerticalScrollBarVisibility();
UpdateItemsUpdatingScrollMode();
UpdateFlowDirection();
UpdateVisibility();

// Listen for ScrollTo requests
newElement.ScrollToRequested += ScrollToRequested;
Expand Down Expand Up @@ -142,6 +147,11 @@ protected virtual void UpdateItemsSource()
Controller.UpdateItemsSource();
}

protected virtual void UpdateVisibility()
{
Controller?.UpdateVisibility();
}

protected abstract TViewController CreateController(TItemsView newElement, ItemsViewLayout layout);

NSIndexPath DetermineIndex(ScrollToRequestEventArgs args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ void CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
void CollectionChanged(NotifyCollectionChangedEventArgs args)
{
switch (args.Action)

{
case NotifyCollectionChangedAction.Add:
Add(args);
Expand All @@ -168,6 +167,11 @@ void Reload()
{
ResetGroupTracking();

if (_collectionView.Hidden)
{
return;
}

_collectionView.ReloadData();
_collectionView.CollectionViewLayout.InvalidateLayout();
}
Expand Down Expand Up @@ -200,7 +204,7 @@ void Add(NotifyCollectionChangedEventArgs args)
ResetGroupTracking();

// Queue up the updates to the UICollectionView
_collectionView.InsertSections(CreateIndexSetFrom(startIndex, count));
Update(() => _collectionView.InsertSections(CreateIndexSetFrom(startIndex, count)));
}

void Remove(NotifyCollectionChangedEventArgs args)
Expand Down Expand Up @@ -229,7 +233,7 @@ void Remove(NotifyCollectionChangedEventArgs args)
var count = args.OldItems.Count;

// Queue up the updates to the UICollectionView
_collectionView.DeleteSections(CreateIndexSetFrom(startIndex, count));
Update(() => _collectionView.DeleteSections(CreateIndexSetFrom(startIndex, count)));
}

void Replace(NotifyCollectionChangedEventArgs args)
Expand All @@ -243,7 +247,7 @@ void Replace(NotifyCollectionChangedEventArgs args)
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _groupSource.IndexOf(args.NewItems[0]);

// We are replacing one set of items with a set of equal size; we can do a simple item range update
_collectionView.ReloadSections(CreateIndexSetFrom(startIndex, newCount));
Update(() => _collectionView.ReloadSections(CreateIndexSetFrom(startIndex, newCount)));
return;
}

Expand All @@ -261,14 +265,14 @@ void Move(NotifyCollectionChangedEventArgs args)
if (count == 1)
{
// For a single item, we can use MoveSection and get the animation
_collectionView.MoveSection(args.OldStartingIndex, args.NewStartingIndex);
Update(() => _collectionView.MoveSection(args.OldStartingIndex, args.NewStartingIndex));
return;
}

var start = Math.Min(args.OldStartingIndex, args.NewStartingIndex);
var end = Math.Max(args.OldStartingIndex, args.NewStartingIndex) + count;

_collectionView.ReloadSections(CreateIndexSetFrom(start, end));
Update(() => _collectionView.ReloadSections(CreateIndexSetFrom(start, end)));
}

int GetGroupCount(int groupIndex)
Expand Down Expand Up @@ -343,5 +347,15 @@ bool ReloadRequired()
return NotLoadedYet()
|| _collectionView.NumberOfSections() == 0;
}

void Update(Action update)
{
if (_collectionView.Hidden)
{
return;
}

update();
}
}
}
30 changes: 15 additions & 15 deletions Xamarin.Forms.Platform.iOS/CollectionView/ObservableItemsSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,6 @@ void CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)

void CollectionChanged(NotifyCollectionChangedEventArgs args)
{
if (CollectionView.NumberOfSections() == 0)
{
// The CollectionView isn't fully initialized yet
return;
}

// Force UICollectionView to get the internal accounting straight
CollectionView.NumberOfItemsInSection(_section);

Expand Down Expand Up @@ -144,6 +138,11 @@ void CollectionChanged(NotifyCollectionChangedEventArgs args)

void Reload()
{
if (CollectionView.Hidden)
{
return;
}

var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);

Count = ItemsCount();
Expand Down Expand Up @@ -199,9 +198,8 @@ void Replace(NotifyCollectionChangedEventArgs args)
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : IndexOf(args.NewItems[0]);

// We are replacing one set of items with a set of equal size; we can do a simple item range update
OnCollectionViewUpdating(args);
CollectionView.ReloadItems(CreateIndexesFrom(startIndex, newCount));
OnCollectionViewUpdated(args);

Update(() => CollectionView.ReloadItems(CreateIndexesFrom(startIndex, newCount)), args);
return;
}

Expand All @@ -220,18 +218,14 @@ void Move(NotifyCollectionChangedEventArgs args)
var oldPath = NSIndexPath.Create(_section, args.OldStartingIndex);
var newPath = NSIndexPath.Create(_section, args.NewStartingIndex);

OnCollectionViewUpdating(args);
CollectionView.MoveItem(oldPath, newPath);
OnCollectionViewUpdated(args);
Update(() => CollectionView.MoveItem(oldPath, newPath), args);
return;
}

var start = Math.Min(args.OldStartingIndex, args.NewStartingIndex);
var end = Math.Max(args.OldStartingIndex, args.NewStartingIndex) + count;
OnCollectionViewUpdating(args);
CollectionView.ReloadItems(CreateIndexesFrom(start, end));

OnCollectionViewUpdated(args);
Update(() => CollectionView.ReloadItems(CreateIndexesFrom(start, end)), args);
}

internal int ItemsCount()
Expand Down Expand Up @@ -276,8 +270,14 @@ internal int IndexOf(object item)

return -1;
}

void Update(Action update, NotifyCollectionChangedEventArgs args)
{
if (CollectionView.Hidden)
{
return;
}

OnCollectionViewUpdating(args);
update();
OnCollectionViewUpdated(args);
Expand Down

0 comments on commit ac9dde6

Please sign in to comment.