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

Fixed CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but not on mobile devices #26152

Merged
merged 3 commits into from
Dec 4, 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 @@ -155,21 +155,8 @@ protected override UICollectionViewLayout SelectLayout()

var itemSizingStrategy = ItemsView.ItemSizingStrategy;
var itemsLayout = ItemsView.ItemsLayout;

//TODO: Find a better way to do this
itemsLayout.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == nameof(ItemsLayout.SnapPointsAlignment) ||
args.PropertyName == nameof(ItemsLayout.SnapPointsType) ||
args.PropertyName == nameof(GridItemsLayout.VerticalItemSpacing) ||
args.PropertyName == nameof(GridItemsLayout.HorizontalItemSpacing) ||
args.PropertyName == nameof(GridItemsLayout.Span) ||
args.PropertyName == nameof(LinearItemsLayout.ItemSpacing))

{
UpdateLayout();
}
};

SubscribeToItemsLayoutPropertyChanged(itemsLayout);

if (itemsLayout is GridItemsLayout gridItemsLayout)
{
Expand All @@ -182,7 +169,10 @@ protected override UICollectionViewLayout SelectLayout()
}

// Fall back to vertical list
return LayoutFactory2.CreateList(new LinearItemsLayout(ItemsLayoutOrientation.Vertical), groupInfo, headerFooterInfo);
var fallbackItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical);
// Manually setting the value to ensure the property changed event is properly wired..
ItemsView.ItemsLayout = fallbackItemsLayout;
return LayoutFactory2.CreateList(fallbackItemsLayout, groupInfo, headerFooterInfo);
}

public static void MapHeaderTemplate(CollectionViewHandler2 handler, StructuredItemsView itemsView)
Expand All @@ -206,5 +196,25 @@ public static void MapItemSizingStrategy(CollectionViewHandler2 handler, Structu
{
handler.UpdateLayout();
}

void SubscribeToItemsLayoutPropertyChanged(IItemsLayout itemsLayout)
{
if(itemsLayout is not null)
{
itemsLayout.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == nameof(ItemsLayout.SnapPointsAlignment) ||
args.PropertyName == nameof(ItemsLayout.SnapPointsType) ||
args.PropertyName == nameof(GridItemsLayout.VerticalItemSpacing) ||
args.PropertyName == nameof(GridItemsLayout.HorizontalItemSpacing) ||
args.PropertyName == nameof(GridItemsLayout.Span) ||
args.PropertyName == nameof(LinearItemsLayout.ItemSpacing))

{
UpdateLayout();
}
};
}
}
}
}
33 changes: 33 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26065.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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"
xmlns:local="clr-namespace:Maui.Controls.Sample"
x:Class="Maui.Controls.Sample.Issues.Issue26065">

<Grid RowDefinitions="Auto,*">
<Button AutomationId="ToggleButton" x:Name="btn" Clicked="Button_Clicked" Text="Modify Itemspacing" Grid.Row="0"/>
<local:CollectionView2 x:Name="collView" AutomationId="CollectionView"
ItemsLayout="{OnIdiom Tablet='VerticalGrid, 2'}"
Grid.Row="1"
ItemsSource="{Binding Books}"
VerticalOptions="Fill">

<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10"
Background="White">
<VerticalStackLayout>
<Label Text="{Binding Title}"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding Author}"
FontSize="14"
TextColor="Gray"/>
</VerticalStackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</local:CollectionView2>
</Grid>

</ContentPage>
68 changes: 68 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26065.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Collections.ObjectModel;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 26065, "CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but NOT Phone", PlatformAffected.iOS)]
public partial class Issue26065 : ContentPage
{
public Issue26065()
{
InitializeComponent();BindingContext = new BookViewModel();
}


private void Button_Clicked(object sender, EventArgs e)
{
if(collView.ItemsLayout is LinearItemsLayout linearItemsLayout)
{
linearItemsLayout.ItemSpacing = 20;
}
}
}

public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}

// ViewModel
public class BookViewModel
{
private ObservableCollection<Book> _bookGroups;
public ObservableCollection<Book> Books
{
get => _bookGroups;
set
{
_bookGroups = value;

}
}

public BookViewModel()
{
LoadBooks();
}

private void LoadBooks()
{
Books = new ObservableCollection<Book>
{

new Book { Title = "Dune", Author = "Frank Herbert" },
new Book { Title = "Neuromancer", Author = "William Gibson" },


new Book { Title = "The Hobbit", Author = "J.R.R. Tolkien" },
new Book { Title = "Name of the Wind", Author = "Patrick Rothfuss" },


new Book { Title = "Murder on the Orient Express", Author = "Agatha Christie" },
new Book { Title = "The Girl with the Dragon Tattoo", Author = "Stieg Larsson" }

};
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#if IOS // Issue occurs only in CollectionViewHandler2

using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue26065 : _IssuesUITest
{
public Issue26065(TestDevice device) : base(device) { }

public override string Issue => "CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but NOT Phone";

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewShouldUseFallBackItemsLayout()
{
App.WaitForElement("CollectionView");
}

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewWithFallbackVauleShouldUpdateAtRunTime()
{
App.WaitForElement("ToggleButton");
App.Tap("ToggleButton");
VerifyScreenshot();
}

}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading