Skip to content

Commit 9055699

Browse files
authored
Ensure disconnected ItemsViewHandler doesn't hold onto the items source (#24699)
* Ensure disconnected ItemsViewHandler doesn't hold onto the items source * Update CarouselViewTests.cs
1 parent 0548772 commit 9055699

File tree

5 files changed

+75
-6
lines changed

5 files changed

+75
-6
lines changed

src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public partial class CarouselViewHandler : ItemsViewHandler<CarouselView>
3838
protected override void ConnectHandler(ListViewBase platformView)
3939
{
4040
ItemsView.Scrolled += CarouselScrolled;
41-
ListViewBase.SizeChanged += OnListViewSizeChanged;
41+
platformView.SizeChanged += OnListViewSizeChanged;
4242

4343
UpdateScrollBarVisibilityForLoop();
4444

@@ -50,9 +50,9 @@ protected override void DisconnectHandler(ListViewBase platformView)
5050
if (ItemsView != null)
5151
ItemsView.Scrolled -= CarouselScrolled;
5252

53-
if (ListViewBase != null)
53+
if (platformView != null)
5454
{
55-
ListViewBase.SizeChanged -= OnListViewSizeChanged;
55+
platformView.SizeChanged -= OnListViewSizeChanged;
5656
_proxy.Unsubscribe();
5757
}
5858

src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ protected override void ConnectHandler(ListViewBase platformView)
5757
protected override void DisconnectHandler(ListViewBase platformView)
5858
{
5959
VirtualView.ScrollToRequested -= ScrollToRequested;
60+
CleanUpCollectionViewSource(platformView);
6061
base.DisconnectHandler(platformView);
6162
}
6263

@@ -154,6 +155,11 @@ void OnItemsVectorChanged(global::Windows.Foundation.Collections.IObservableVect
154155
protected abstract ListViewBase SelectListViewBase();
155156

156157
protected virtual void CleanUpCollectionViewSource()
158+
{
159+
CleanUpCollectionViewSource(ListViewBase);
160+
}
161+
162+
private void CleanUpCollectionViewSource(ListViewBase platformView)
157163
{
158164
if (CollectionViewSource is not null)
159165
{
@@ -174,7 +180,7 @@ protected virtual void CleanUpCollectionViewSource()
174180
// Remove all children inside the ItemsSource
175181
if (VirtualView is not null)
176182
{
177-
foreach (var item in ListViewBase.GetChildren<ItemContentControl>())
183+
foreach (var item in platformView.GetChildren<ItemContentControl>())
178184
{
179185
var element = item.GetVisualElement();
180186
VirtualView.RemoveLogicalChild(element);
@@ -183,7 +189,7 @@ protected virtual void CleanUpCollectionViewSource()
183189

184190
if (VirtualView?.ItemsSource is null)
185191
{
186-
ListViewBase.ItemsSource = null;
192+
platformView.ItemsSource = null;
187193
return;
188194
}
189195
}

src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public abstract partial class ItemsViewHandler<TItemsView> : ViewHandler<TItemsV
1717
protected override void DisconnectHandler(UIView platformView)
1818
{
1919
ItemsView.ScrollToRequested -= ScrollToRequested;
20+
Controller?.DisposeItemsSource();
2021
base.DisconnectHandler(platformView);
2122
}
2223

src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs

+9
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,15 @@ public virtual void UpdateItemsSource()
329329
(ItemsView as IView)?.InvalidateMeasure();
330330
}
331331

332+
internal void DisposeItemsSource()
333+
{
334+
_measurementCells?.Clear();
335+
ItemsViewLayout?.ClearCellSizeCache();
336+
ItemsSource?.Dispose();
337+
ItemsSource = new EmptySource();
338+
CollectionView.ReloadData();
339+
}
340+
332341
public virtual void UpdateFlowDirection()
333342
{
334343
CollectionView.UpdateFlowDirection(ItemsView);

src/Controls/tests/DeviceTests/Elements/CarouselView/CarouselViewTests.cs

+54-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.ObjectModel;
2+
using System.Collections.Specialized;
23
using System.Threading.Tasks;
34
using Microsoft.Maui.Controls;
45
using Microsoft.Maui.Controls.Handlers.Items;
@@ -112,6 +113,45 @@ await CreateHandlerAndAddToWindow<LayoutHandler>(layout, async (handler) =>
112113
Assert.NotNull(handler.PlatformView);
113114
});
114115
}
116+
117+
#if !ANDROID //https://github.com/dotnet/maui/pull/24610
118+
[Fact]
119+
public async void DisconnectedCarouselViewDoesNotHookCollectionViewChanged()
120+
{
121+
SetupBuilder();
122+
123+
CollectionChangedObservableCollection<int> data = new CollectionChangedObservableCollection<int>()
124+
{
125+
1,
126+
2,
127+
};
128+
129+
var template = new DataTemplate(() =>
130+
{
131+
return new Grid()
132+
{
133+
new Label()
134+
};
135+
});
136+
137+
var carouselView = new CarouselView()
138+
{
139+
ItemTemplate = template,
140+
ItemsSource = data
141+
};
142+
143+
await CreateHandlerAndAddToWindow<CarouselViewHandler>(carouselView, async (handler) =>
144+
{
145+
await Task.Delay(100);
146+
Assert.NotNull(handler.PlatformView);
147+
Assert.False(data.IsCollectionChangedEventEmpty);
148+
});
149+
150+
carouselView.Handler?.DisconnectHandler();
151+
152+
Assert.True(data.IsCollectionChangedEventEmpty);
153+
}
154+
#endif
115155
}
116156

117157
internal class CustomDataTemplateSelectorSelector : DataTemplateSelector
@@ -129,4 +169,17 @@ protected override DataTemplate OnSelectTemplate(object item, BindableObject con
129169
return Template2;
130170
}
131171
}
132-
}
172+
173+
internal class CollectionChangedObservableCollection<T> : ObservableCollection<T>, INotifyCollectionChanged
174+
{
175+
NotifyCollectionChangedEventHandler collectionChanged;
176+
177+
event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
178+
{
179+
add { collectionChanged += value; base.CollectionChanged += value; }
180+
remove { collectionChanged -= value; base.CollectionChanged -= value; }
181+
}
182+
183+
public bool IsCollectionChangedEventEmpty => collectionChanged is null;
184+
}
185+
}

0 commit comments

Comments
 (0)