diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewGallery.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewGallery.cs
index d08ca966315f..39f511cee8ec 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewGallery.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewGallery.cs
@@ -31,6 +31,8 @@ public EmptyViewGallery()
new EmptyViewTemplateGallery(), Navigation),
GalleryBuilder.NavButton("EmptyView (Swap EmptyView)", () =>
new EmptyViewSwapGallery(), Navigation),
+ GalleryBuilder.NavButton("EmptyView (Data Template Selector)", () =>
+ new EmptyViewWithDataTemplateSelector(), Navigation),
GalleryBuilder.NavButton("EmptyView (load simulation)", () =>
new EmptyViewLoadSimulateGallery(), Navigation),
GalleryBuilder.NavButton("EmptyView RTL", () =>
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml
new file mode 100644
index 000000000000..9e7fad850d31
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml.cs
new file mode 100644
index 000000000000..3cf229703706
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/EmptyViewGalleries/EmptyViewWithDataTemplateSelector.xaml.cs
@@ -0,0 +1,75 @@
+#nullable enable
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Xaml;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+
+namespace Maui.Controls.Sample.Pages.CollectionViewGalleries.EmptyViewGalleries
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class EmptyViewWithDataTemplateSelector : ContentPage
+ {
+ public EmptyViewWithDataTemplateSelector()
+ {
+ InitializeComponent();
+ var emptyViewTemplateSelector = new SearchTermDataTemplateSelector
+ {
+ DefaultTemplate = (DataTemplate)Resources["AdvancedTemplate"],
+ OtherTemplate = (DataTemplate)Resources["BasicTemplate"]
+ };
+ collectionView.EmptyViewTemplate = emptyViewTemplateSelector;
+ BindingContext = new EmptyViewWithDataTemplateSelectorViewModel();
+ }
+
+ public class Monkey
+ {
+ public string? Name { get; set; }
+ public string? Location { get; set; }
+ public string? Details { get; set; }
+ }
+
+ public class SearchTermDataTemplateSelector : DataTemplateSelector
+ {
+ public DataTemplate? DefaultTemplate { get; set; }
+ public DataTemplate? OtherTemplate { get; set; }
+
+ protected override DataTemplate? OnSelectTemplate(object item, BindableObject container)
+ {
+ string query = (string)item;
+ return query.Equals("xamarin", StringComparison.OrdinalIgnoreCase) ? OtherTemplate : DefaultTemplate;
+ }
+ }
+
+ internal class EmptyViewWithDataTemplateSelectorViewModel
+ {
+ public ObservableCollection Monkeys { get; } = new();
+ public ICommand FilterCommand => new Command(FilterItems);
+
+ public EmptyViewWithDataTemplateSelectorViewModel()
+ {
+ // Directly populate the ObservableCollection
+ Monkeys.Add(new Monkey
+ {
+ Name = "Baboon",
+ Location = "Africa & Asia",
+ Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae."
+ });
+ }
+
+ private void FilterItems(string filter)
+ {
+ var filteredItems = Monkeys.Where(monkey => monkey.Name?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false).ToList();
+ Monkeys.Clear();
+ foreach (var monkey in filteredItems)
+ {
+ Monkeys.Add(monkey);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
index 72de6841000a..0a925c31b9e0 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
@@ -567,7 +567,7 @@ protected virtual void HandleFormsElementMeasureInvalidated(VisualElement formsE
internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
{
// Is view set on the ItemsView?
- if (view is null && viewTemplate is null)
+ if (view is null && (viewTemplate is null || viewTemplate is DataTemplateSelector))
{
if (formsElement != null)
{
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
index 742972bb9941..d827de4b9b60 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
@@ -401,7 +401,7 @@ protected virtual CGRect DetermineEmptyViewFrame()
internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
{
// Is view set on the ItemsView?
- if (view == null && viewTemplate is null)
+ if (view is null && (viewTemplate is null || viewTemplate is DataTemplateSelector))
{
if (formsElement != null)
{
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml
new file mode 100644
index 000000000000..1b35e0b3835a
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml.cs
new file mode 100644
index 000000000000..8d44ee93e2ac
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue25224.xaml.cs
@@ -0,0 +1,64 @@
+#nullable enable
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+
+namespace Maui.Controls.Sample.Issues
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ [Issue(IssueTracker.Github, 25224, "CollectionView - EmptyView with EmptyViewTemplate for Data template selector page throws an exception", PlatformAffected.iOS)]
+ public partial class Issue25224: ContentPage
+ {
+ public Issue25224()
+ {
+ InitializeComponent();
+ var emptyViewTemplateSelector = new SearchTermDataTemplateSelector
+ {
+ DefaultTemplate = (DataTemplate)Resources["AdvancedTemplate"],
+ OtherTemplate = (DataTemplate)Resources["BasicTemplate"]
+ };
+ collectionView.EmptyViewTemplate = emptyViewTemplateSelector;
+ BindingContext = new Issue25224ViewModel();
+ }
+
+ public class SearchTermDataTemplateSelector : DataTemplateSelector
+ {
+ public DataTemplate? DefaultTemplate { get; set; }
+ public DataTemplate? OtherTemplate { get; set; }
+
+ protected override DataTemplate? OnSelectTemplate(object item, BindableObject container)
+ {
+ string query = (string)item;
+ return query.Equals("xamarin", StringComparison.OrdinalIgnoreCase) ? OtherTemplate : DefaultTemplate;
+ }
+ }
+
+ internal class Issue25224ViewModel
+ {
+ public ObservableCollection Monkeys { get; } = new();
+ public ICommand FilterCommand => new Command(FilterItems);
+
+ public Issue25224ViewModel()
+ {
+ // Directly populate the ObservableCollection
+ Monkeys.Add(new Monkey
+ {
+ Name = "Baboon",
+ Location = "Africa & Asia",
+ Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae."
+ });
+ }
+
+ private void FilterItems(string filter)
+ {
+ var filteredItems = Monkeys.Where(monkey => monkey.Name?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false).ToList();
+ Monkeys.Clear();
+ foreach (var monkey in filteredItems)
+ {
+ Monkeys.Add(monkey);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25224.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25224.cs
new file mode 100644
index 000000000000..2623b850b409
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25224.cs
@@ -0,0 +1,36 @@
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues
+{
+ internal class Issue25224 : _IssuesUITest
+ {
+ public Issue25224(TestDevice device) : base(device) { }
+
+ public override string Issue => "CollectionView - EmptyView with EmptyViewTemplate for Data template selector page throws an exception";
+
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void CollectionViewEmptyViewDefaultTemplateShouldNotCrashOnDisplay()
+ {
+ App.WaitForElement("SearchBar");
+ App.EnterText("SearchBar", "test");
+ App.PressEnter();
+ // On UI test, pressing Enter twice performs filtering and shows the empty view.
+ // This code is necessary due to the app's behavior on UI test, which differs from simple samples.
+ App.PressEnter();
+ App.WaitForElement("Success");
+ }
+
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void CollectionViewEmptyViewOtherTemplateShouldNotCrashOnDisplay()
+ {
+ App.WaitForElement("SearchBar");
+ App.EnterText("SearchBar", "xamarin");
+ App.PressEnter();
+ App.WaitForElement("Success");
+ }
+ }
+}
\ No newline at end of file