Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "[iOS] Clear BindingContext when cell is queued for reuse (#14… #21400

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions src/Controls/src/Core/Handlers/Items/iOS/ItemsViewDelegator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,6 @@ public override nfloat GetMinimumLineSpacingForSection(UICollectionView collecti

public override void CellDisplayingEnded(UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
{
if (cell is TemplatedCell templatedCell &&
(templatedCell.PlatformHandler?.VirtualView as View)?.BindingContext is object bindingContext)
{
// We want to unbind a cell that is no longer present in the items source. Unfortunately
// it's too expensive to check directly, so let's check that the current binding context
// matches the item at a given position.

var itemsSource = ViewController?.ItemsSource;
if (itemsSource is null ||
!itemsSource.IsIndexPathValid(indexPath) ||
!Equals(itemsSource[indexPath], bindingContext))
{
templatedCell.Unbind();
}
}
}

protected virtual (bool VisibleItems, NSIndexPath First, NSIndexPath Center, NSIndexPath Last) GetVisibleItemsIndexPath()
Expand Down Expand Up @@ -181,4 +166,4 @@ public override CGSize GetSizeForItem(UICollectionView collectionView, UICollect
return ViewController?.GetSizeForItem(indexPath) ?? CGSize.Empty;
}
}
}
}
29 changes: 11 additions & 18 deletions src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,6 @@ protected void ClearConstraints()
ConstrainedDimension = default;
}

internal void Unbind()
{
if (PlatformHandler?.VirtualView is View view)
{
view.MeasureInvalidated -= MeasureInvalidated;
view.BindingContext = null;
}
}

public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittingAttributes(
UICollectionViewLayoutAttributes layoutAttributes)
{
Expand Down Expand Up @@ -125,12 +116,6 @@ protected void Layout(CGSize constraints)
_size = rectangle.Size;
}

public override void PrepareForReuse()
{
Unbind();
base.PrepareForReuse();
}

public void Bind(DataTemplate template, object bindingContext, ItemsView itemsView)
{
var oldElement = PlatformHandler?.VirtualView as View;
Expand Down Expand Up @@ -172,10 +157,18 @@ public void Bind(DataTemplate template, object bindingContext, ItemsView itemsVi
// Same template
if (oldElement != null)
{
oldElement.BindingContext = bindingContext;
oldElement.MeasureInvalidated += MeasureInvalidated;
if (oldElement.BindingContext == null || !(oldElement.BindingContext.Equals(bindingContext)))
{
// If the data is different, update it

UpdateCellSize();
// Unhook the MeasureInvalidated handler, otherwise it'll fire for every invalidation during the
// BindingContext change
oldElement.MeasureInvalidated -= MeasureInvalidated;
oldElement.BindingContext = bindingContext;
oldElement.MeasureInvalidated += MeasureInvalidated;

UpdateCellSize();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ Microsoft.Maui.Controls.Region.Equals(Microsoft.Maui.Controls.Region other) -> b
Microsoft.Maui.Controls.Shapes.Matrix.Equals(Microsoft.Maui.Controls.Shapes.Matrix other) -> bool
Microsoft.Maui.Controls.Shapes.Shape.~Shape() -> void
Microsoft.Maui.Controls.VisualElement.~VisualElement() -> void
override Microsoft.Maui.Controls.Handlers.Items.TemplatedCell.PrepareForReuse() -> void
override Microsoft.Maui.Controls.Handlers.Compatibility.PhoneFlyoutPageRenderer.ViewWillLayoutSubviews() -> void
override Microsoft.Maui.Controls.LayoutOptions.GetHashCode() -> int
override Microsoft.Maui.Controls.Platform.Compatibility.ShellPageRendererTracker.TitleViewContainer.LayoutSubviews() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ Microsoft.Maui.Controls.Region.Equals(Microsoft.Maui.Controls.Region other) -> b
Microsoft.Maui.Controls.Shapes.Matrix.Equals(Microsoft.Maui.Controls.Shapes.Matrix other) -> bool
Microsoft.Maui.Controls.Shapes.Shape.~Shape() -> void
Microsoft.Maui.Controls.VisualElement.~VisualElement() -> void
override Microsoft.Maui.Controls.Handlers.Items.TemplatedCell.PrepareForReuse() -> void
override Microsoft.Maui.Controls.Handlers.Compatibility.PhoneFlyoutPageRenderer.ViewWillLayoutSubviews() -> void
override Microsoft.Maui.Controls.LayoutOptions.GetHashCode() -> int
override Microsoft.Maui.Controls.Platform.Compatibility.ShellPageRendererTracker.TitleViewContainer.LayoutSubviews() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,71 +397,7 @@ static async Task WaitForUIUpdate(Rect frame, CollectionView collectionView, int
timeout -= interval;
}
}

[Fact]
public async Task ClearingItemsSourceClearsBindingContext()
{
SetupBuilder();

IReadOnlyList<Element> logicalChildren = null;
var collectionView = new CollectionView
{
ItemTemplate = new DataTemplate(() => new Label() { HeightRequest = 30, WidthRequest = 200 }),
WidthRequest = 200,
HeightRequest = 200,
};

await CreateHandlerAndAddToWindow<CollectionViewHandler>(collectionView, async handler =>
{
var data = new ObservableCollection<MyRecord>()
{
new MyRecord("Item 1"),
new MyRecord("Item 2"),
new MyRecord("Item 3"),
};
collectionView.ItemsSource = data;
await Task.Delay(100);

logicalChildren = collectionView.LogicalChildrenInternal;
Assert.NotNull(logicalChildren);
Assert.True(logicalChildren.Count == 3);

// Clear collection
var savedItems = data.ToArray();
data.Clear();

await Task.Delay(100);

// Check that all logical children have no binding context
foreach (var logicalChild in logicalChildren)
{
Assert.Null(logicalChild.BindingContext);
}

// Re-add the old children
foreach (var savedItem in savedItems)
{
data.Add(savedItem);
}

await Task.Delay(100);

// Check that the right number of logical children have binding context again
int boundChildren = 0;
foreach (var logicalChild in logicalChildren)
{
if (logicalChild.BindingContext is not null)
{
boundChildren++;
}
}
Assert.Equal(3, boundChildren);
});
}

record MyRecord(string Name);



[Fact]
public async Task SettingSelectedItemAfterModifyingCollectionDoesntCrash()
{
Expand Down
Loading