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

[iOS] Add templated cells as children of the CollectionView2 #26357

Merged
merged 5 commits into from
Dec 6, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -211,83 +211,6 @@ internal void DisposeItemsSource()
CollectionView.ReloadData();
}

// void InvalidateMeasureIfContentSizeChanged()
// {
// var contentSize = CollectionView?.CollectionViewLayout?.CollectionViewContentSize;
//
// if (!contentSize.HasValue)
// {
// return;
// }
//
// bool widthChanged = _previousContentSize.Width != contentSize.Value.Width;
// bool heightChanged = _previousContentSize.Height != contentSize.Value.Height;
//
// if (_initialized && (widthChanged || heightChanged))
// {
// var screenFrame = CollectionView?.Window?.Frame;
//
// if (!screenFrame.HasValue)
// {
// return;
// }
//
// var screenWidth = screenFrame.Value.Width;
// var screenHeight = screenFrame.Value.Height;
// bool invalidate = false;
//
// // If both the previous content size and the current content size are larger
// // than the screen size, then we know that we're already maxed out and the
// // CollectionView items are scrollable. There's no reason to force an invalidation
// // of the CollectionView to expand/contract it.
//
// // If either size is smaller than that, we need to invalidate to ensure that the
// // CollectionView is re-measured and set to the correct size.
//
// if (widthChanged && (contentSize.Value.Width < screenWidth || _previousContentSize.Width < screenWidth))
// {
// invalidate = true;
// }
//
// if (heightChanged && (contentSize.Value.Height < screenHeight || _previousContentSize.Height < screenHeight))
// {
// invalidate = true;
// }
//
// if (invalidate)
// {
// (ItemsView as IView)?.InvalidateMeasure();
// }
// }
// _previousContentSize = contentSize.Value;
// }

const int HeaderTag = 111;

// internal Size? GetSize()
// {
// if (_emptyViewDisplayed)
// {
// return _emptyUIView.Frame.Size.ToSize();
// }

// nfloat headerHeight = 0;
// var headerView = CollectionView.ViewWithTag(HeaderTag);

// if (headerView != null)
// headerHeight = headerView.Frame.Height;

// var sizeColl = CollectionView.CollectionViewLayout.CollectionViewContentSize;
// return sizeColl.ToSize();
// }

// void ConstrainItemsToBounds()
// {
// var contentBounds = CollectionView.AdjustedContentInset.InsetRect(CollectionView.Bounds);
// var constrainedSize = contentBounds.Size;
// ItemsViewLayout.UpdateConstraints(constrainedSize);
// }

void EnsureLayoutInitialized()
{
if (_initialized)
Expand Down Expand Up @@ -370,7 +293,6 @@ protected virtual string DetermineCellReuseId(NSIndexPath indexPath)

if (!_cellReuseIds.Contains(reuseId))
{
Console.WriteLine($"REGISTER CELL ID: {reuseId}");
CollectionView.RegisterClassForCell(cellType, new NSString(reuseId));
_cellReuseIds.Add(reuseId);
}
Expand Down Expand Up @@ -408,9 +330,8 @@ internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiVi
//Platform.GetRenderer(formsElement)?.DisposeRendererAndChildren();
}

uiView?.Dispose();
uiView = null;

formsElement?.Handler?.DisconnectHandler();
rmarinho marked this conversation as resolved.
Show resolved Hide resolved
formsElement = null;
}
else
Expand Down
49 changes: 21 additions & 28 deletions src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ internal void Unbind()
{
//view.MeasureInvalidated -= MeasureInvalidated;
view.BindingContext = null;
(view.Parent as ItemsView)?.RemoveLogicalChild(view);
}
}

Expand Down Expand Up @@ -107,49 +108,41 @@ public override void PrepareForReuse()

public void Bind(DataTemplate template, object bindingContext, ItemsView itemsView)
{
if (PlatformHandler is null)
{
var virtualView = template.CreateContent(bindingContext, itemsView) as View;

var mauiContext = itemsView.FindMauiContext()!;
var nativeView = virtualView!.ToPlatform(mauiContext);

PlatformView = nativeView;

PlatformHandler = virtualView.Handler as IPlatformViewHandler;

InitializeContentConstraints(nativeView);

virtualView.BindingContext = bindingContext;
}

if (PlatformHandler?.VirtualView is View view)
{
view.SetValueFromRenderer(BindableObject.BindingContextProperty, bindingContext);
}
var virtualView = template.CreateContent(bindingContext, itemsView) as View;
BindVirtualView(virtualView, bindingContext, itemsView, false);
}

public void Bind(View virtualView, ItemsView itemsView)
{
BindVirtualView(virtualView, itemsView.BindingContext, itemsView, true);
}

void BindVirtualView(View virtualView, object bindingContext, ItemsView itemsView, bool needsContainer)
{
if (PlatformHandler is null && virtualView is not null)
{
var mauiContext = itemsView.FindMauiContext()!;
var nativeView = virtualView!.ToPlatform(mauiContext);
var nativeView = virtualView.ToPlatform(mauiContext);

var mauiWrapperView = new UIContainerView2(virtualView, mauiContext);

PlatformView = mauiWrapperView;
if (needsContainer)
{
PlatformView = new UIContainerView2(virtualView, mauiContext);
}
else
{
PlatformView = nativeView;
}

PlatformHandler = virtualView.Handler as IPlatformViewHandler;
InitializeContentConstraints(PlatformView);

InitializeContentConstraints(mauiWrapperView);

virtualView.BindingContext = itemsView.BindingContext;
virtualView.BindingContext = bindingContext;
itemsView.AddLogicalChild(virtualView);
}

if (PlatformHandler?.VirtualView is View view)
{
view.SetValueFromRenderer(BindableObject.BindingContextProperty, itemsView.BindingContext);
view.SetValueFromRenderer(BindableObject.BindingContextProperty, bindingContext);
}
}

Expand Down
42 changes: 42 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26066.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue26066"
xmlns:sample="clr-namespace:Maui.Controls.Sample"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues"
x:DataType="local:Issue26066ViewModel">
<ContentPage.BindingContext>
<local:Issue26066ViewModel/>
</ContentPage.BindingContext>
<Grid RowDefinitions="Auto,*,Auto,*">
<Grid.Resources>
<DataTemplate x:DataType="local:Issue22035Model"
x:Key="template">
<StackLayout Padding="10" BackgroundColor="Lightgray">
<Button
AutomationId="{Binding AutomationId}"
Command="{Binding ShowDialogCommand, Source={x:RelativeSource AncestorType={x:Type local:Issue26066ViewModel}}, x:DataType=local:Issue26066ViewModel}"
CommandParameter="{Binding .}"
Text="{Binding Text}"/>
</StackLayout>
</DataTemplate>
</Grid.Resources>
<Button BackgroundColor="LightBlue"
Grid.Row="0"
AutomationId="TestLoadButtonCV2"
Text="Load Items CV2"
Command="{Binding LoadCommandCV2}"/>
<sample:CollectionView2 Grid.Row="1" BackgroundColor="LightBlue"
ItemsSource="{Binding Images2}"
ItemTemplate="{StaticResource template}"/>
<Button BackgroundColor="LightGreen "
Grid.Row="2"
AutomationId="TestLoadButtonCV"
Text="Load Items CV1"
Command="{Binding LoadCommand}"/>
<sample:CollectionView1 Grid.Row="3" BackgroundColor="LightGreen"
ItemsSource="{Binding Images}"
ItemTemplate="{StaticResource template}"/>
</Grid>
</ContentPage>
42 changes: 42 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26066.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Collections.ObjectModel;
using System.Windows.Input;

namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 26066, "CollectionViewHandler2 RelativeSource binding to AncestorType not working", PlatformAffected.Android | PlatformAffected.iOS)]
public partial class Issue26066 : ContentPage
{
public Issue26066()
{
InitializeComponent();
}
}

class Issue26066ViewModel
{
public Issue26066ViewModel()
{
LoadCommand.Execute(null);
LoadCommandCV2.Execute(null);
}

public ObservableCollection<Issue22035Model> Images { get; set; } = new();
public ObservableCollection<Issue22035Model> Images2 { get; set; } = new();

public ICommand ShowDialogCommand => new Command(async () => await Application.Current.MainPage.DisplayAlert("New Dialog", "Hello from Espinho", "OK"));

public ICommand LoadCommand => new Command(() => LoadItems(Images, "CV1"));

public ICommand LoadCommandCV2 => new Command(() => LoadItems(Images2, "CV2"));

static void LoadItems(ObservableCollection<Issue22035Model> items, string text)
{
items.Clear();
for (int i = 0; i < 3 ; i++)
{
items.Add(new Issue22035Model { Text = $"{text} - Item {i}", ImagePath = i% 2 == 0 ? "photo21314.jpg" : "oasis.jpg" });
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue26066(TestDevice testDevice) : _IssuesUITest(testDevice)
{
public override string Issue => "CollectionViewHandler2 RelativeSource binding to AncestorType not working";

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionView2ShouldFindAncestorType()
{
var text = "CV2";
var i = 1;
var automationId = $"{text} - Item {i}".Replace(" ", "", StringComparison.Ordinal);
App.WaitForElement(automationId);
App.Click(automationId);
App.WaitForElement("OK");
App.Click("OK");
}
}
Loading