Skip to content

Commit 0ddc794

Browse files
Fixed CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but not on mobile devices (#26152)
* Fixed CollectionViewHandler2 null reference exception * Removed unnecessary code changes * Modified code changes and added test case images
1 parent a57ab5d commit 0ddc794

File tree

5 files changed

+159
-16
lines changed

5 files changed

+159
-16
lines changed

src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -155,21 +155,8 @@ protected override UICollectionViewLayout SelectLayout()
155155

156156
var itemSizingStrategy = ItemsView.ItemSizingStrategy;
157157
var itemsLayout = ItemsView.ItemsLayout;
158-
159-
//TODO: Find a better way to do this
160-
itemsLayout.PropertyChanged += (sender, args) =>
161-
{
162-
if (args.PropertyName == nameof(ItemsLayout.SnapPointsAlignment) ||
163-
args.PropertyName == nameof(ItemsLayout.SnapPointsType) ||
164-
args.PropertyName == nameof(GridItemsLayout.VerticalItemSpacing) ||
165-
args.PropertyName == nameof(GridItemsLayout.HorizontalItemSpacing) ||
166-
args.PropertyName == nameof(GridItemsLayout.Span) ||
167-
args.PropertyName == nameof(LinearItemsLayout.ItemSpacing))
168-
169-
{
170-
UpdateLayout();
171-
}
172-
};
158+
159+
SubscribeToItemsLayoutPropertyChanged(itemsLayout);
173160

174161
if (itemsLayout is GridItemsLayout gridItemsLayout)
175162
{
@@ -182,7 +169,10 @@ protected override UICollectionViewLayout SelectLayout()
182169
}
183170

184171
// Fall back to vertical list
185-
return LayoutFactory2.CreateList(new LinearItemsLayout(ItemsLayoutOrientation.Vertical), groupInfo, headerFooterInfo);
172+
var fallbackItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical);
173+
// Manually setting the value to ensure the property changed event is properly wired..
174+
ItemsView.ItemsLayout = fallbackItemsLayout;
175+
return LayoutFactory2.CreateList(fallbackItemsLayout, groupInfo, headerFooterInfo);
186176
}
187177

188178
public static void MapHeaderTemplate(CollectionViewHandler2 handler, StructuredItemsView itemsView)
@@ -206,5 +196,25 @@ public static void MapItemSizingStrategy(CollectionViewHandler2 handler, Structu
206196
{
207197
handler.UpdateLayout();
208198
}
199+
200+
void SubscribeToItemsLayoutPropertyChanged(IItemsLayout itemsLayout)
201+
{
202+
if(itemsLayout is not null)
203+
{
204+
itemsLayout.PropertyChanged += (sender, args) =>
205+
{
206+
if (args.PropertyName == nameof(ItemsLayout.SnapPointsAlignment) ||
207+
args.PropertyName == nameof(ItemsLayout.SnapPointsType) ||
208+
args.PropertyName == nameof(GridItemsLayout.VerticalItemSpacing) ||
209+
args.PropertyName == nameof(GridItemsLayout.HorizontalItemSpacing) ||
210+
args.PropertyName == nameof(GridItemsLayout.Span) ||
211+
args.PropertyName == nameof(LinearItemsLayout.ItemSpacing))
212+
213+
{
214+
UpdateLayout();
215+
}
216+
};
217+
}
218+
}
209219
}
210220
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:local="clr-namespace:Maui.Controls.Sample"
5+
x:Class="Maui.Controls.Sample.Issues.Issue26065">
6+
7+
<Grid RowDefinitions="Auto,*">
8+
<Button AutomationId="ToggleButton" x:Name="btn" Clicked="Button_Clicked" Text="Modify Itemspacing" Grid.Row="0"/>
9+
<local:CollectionView2 x:Name="collView" AutomationId="CollectionView"
10+
ItemsLayout="{OnIdiom Tablet='VerticalGrid, 2'}"
11+
Grid.Row="1"
12+
ItemsSource="{Binding Books}"
13+
VerticalOptions="Fill">
14+
15+
<CollectionView.ItemTemplate>
16+
<DataTemplate>
17+
<Grid Padding="10"
18+
Background="White">
19+
<VerticalStackLayout>
20+
<Label Text="{Binding Title}"
21+
FontSize="16"
22+
FontAttributes="Bold"/>
23+
<Label Text="{Binding Author}"
24+
FontSize="14"
25+
TextColor="Gray"/>
26+
</VerticalStackLayout>
27+
</Grid>
28+
</DataTemplate>
29+
</CollectionView.ItemTemplate>
30+
</local:CollectionView2>
31+
</Grid>
32+
33+
</ContentPage>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System.Collections.ObjectModel;
2+
3+
namespace Maui.Controls.Sample.Issues
4+
{
5+
[Issue(IssueTracker.Github, 26065, "CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but NOT Phone", PlatformAffected.iOS)]
6+
public partial class Issue26065 : ContentPage
7+
{
8+
public Issue26065()
9+
{
10+
InitializeComponent();BindingContext = new BookViewModel();
11+
}
12+
13+
14+
private void Button_Clicked(object sender, EventArgs e)
15+
{
16+
if(collView.ItemsLayout is LinearItemsLayout linearItemsLayout)
17+
{
18+
linearItemsLayout.ItemSpacing = 20;
19+
}
20+
}
21+
}
22+
23+
public class Book
24+
{
25+
public string Title { get; set; }
26+
public string Author { get; set; }
27+
}
28+
29+
// ViewModel
30+
public class BookViewModel
31+
{
32+
private ObservableCollection<Book> _bookGroups;
33+
public ObservableCollection<Book> Books
34+
{
35+
get => _bookGroups;
36+
set
37+
{
38+
_bookGroups = value;
39+
40+
}
41+
}
42+
43+
public BookViewModel()
44+
{
45+
LoadBooks();
46+
}
47+
48+
private void LoadBooks()
49+
{
50+
Books = new ObservableCollection<Book>
51+
{
52+
53+
new Book { Title = "Dune", Author = "Frank Herbert" },
54+
new Book { Title = "Neuromancer", Author = "William Gibson" },
55+
56+
57+
new Book { Title = "The Hobbit", Author = "J.R.R. Tolkien" },
58+
new Book { Title = "Name of the Wind", Author = "Patrick Rothfuss" },
59+
60+
61+
new Book { Title = "Murder on the Orient Express", Author = "Agatha Christie" },
62+
new Book { Title = "The Girl with the Dragon Tattoo", Author = "Stieg Larsson" }
63+
64+
};
65+
}
66+
}
67+
68+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#if IOS // Issue occurs only in CollectionViewHandler2
2+
3+
using NUnit.Framework;
4+
using UITest.Appium;
5+
using UITest.Core;
6+
namespace Microsoft.Maui.TestCases.Tests.Issues
7+
{
8+
public class Issue26065 : _IssuesUITest
9+
{
10+
public Issue26065(TestDevice device) : base(device) { }
11+
12+
public override string Issue => "CollectionViewHandler2 null reference exception if ItemsLayout is set for Tablet but NOT Phone";
13+
14+
[Test]
15+
[Category(UITestCategories.CollectionView)]
16+
public void CollectionViewShouldUseFallBackItemsLayout()
17+
{
18+
App.WaitForElement("CollectionView");
19+
}
20+
21+
[Test]
22+
[Category(UITestCategories.CollectionView)]
23+
public void CollectionViewWithFallbackVauleShouldUpdateAtRunTime()
24+
{
25+
App.WaitForElement("ToggleButton");
26+
App.Tap("ToggleButton");
27+
VerifyScreenshot();
28+
}
29+
30+
}
31+
}
32+
#endif
82.4 KB
Loading

0 commit comments

Comments
 (0)