diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ItemsControl.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ItemsControl.cs
index d3006dc174aa..fcd8d6298f9b 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ItemsControl.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ItemsControl.cs
@@ -480,6 +480,86 @@ public async Task When_ContentPresenter_ContainerRecycled_And_Explicit_Item()
Assert.IsNotNull(third.ContentTemplateSelector);
}
+ [TestMethod]
+ [RunsOnUIThread]
+ public async Task When_ContentPresenter_ContainerRecycled_And_ContentControl_Template()
+ {
+ var dataTemplate = (DataTemplate)XamlReader.Load(
+ """
+
+
+
+ """);
+
+ var selector = new TestTemplateSelector();
+
+ var source = new[]
+ {
+ "First",
+ "Second",
+ };
+
+ var SUT = new ItemsControl()
+ {
+ ItemsSource = source,
+ ItemTemplate = dataTemplate
+ };
+
+ WindowHelper.WindowContent = SUT;
+
+ await WindowHelper.WaitForIdle();
+
+ {
+ ContentPresenter first = null;
+ await WindowHelper.WaitFor(() => (first = SUT.ContainerFromItem(source[0]) as ContentPresenter) != null);
+
+ ContentPresenter second = null;
+ await WindowHelper.WaitFor(() => (second = SUT.ContainerFromItem(source[1]) as ContentPresenter) != null);
+
+ Assert.IsNotNull(first);
+ Assert.IsNotNull(second);
+
+ Assert.IsNotNull(first.Content);
+ Assert.IsNotNull(second.Content);
+
+ var firstInnerContent = first.ContentTemplateRoot as ContentControl;
+ Assert.AreEqual(source[0], firstInnerContent?.Content);
+ Assert.IsNotNull(firstInnerContent.GetBindingExpression(ContentControl.ContentProperty));
+
+ var secondInnerContent = second.ContentTemplateRoot as ContentControl;
+ Assert.AreEqual(source[1], secondInnerContent.Content);
+ Assert.IsNotNull(secondInnerContent.GetBindingExpression(ContentControl.ContentProperty));
+ }
+
+ SUT.ItemsSource = null;
+ await WindowHelper.WaitForIdle();
+
+ SUT.ItemsSource = source;
+ await WindowHelper.WaitForIdle();
+
+ {
+ ContentPresenter first = null;
+ await WindowHelper.WaitFor(() => (first = SUT.ContainerFromItem(source[0]) as ContentPresenter) != null);
+
+ ContentPresenter second = null;
+ await WindowHelper.WaitFor(() => (second = SUT.ContainerFromItem(source[1]) as ContentPresenter) != null);
+
+ Assert.IsNotNull(first);
+ Assert.IsNotNull(second);
+
+ Assert.IsNotNull(first.Content);
+ Assert.IsNotNull(second.Content);
+
+ var firstInnerContent = first.ContentTemplateRoot as ContentControl;
+ Assert.AreEqual(source[0], firstInnerContent?.Content);
+ Assert.IsNotNull(firstInnerContent.GetBindingExpression(ContentControl.ContentProperty));
+
+ var secondInnerContent = second.ContentTemplateRoot as ContentControl;
+ Assert.AreEqual(source[1], secondInnerContent.Content);
+ Assert.IsNotNull(secondInnerContent.GetBindingExpression(ContentControl.ContentProperty));
+ }
+ }
+
[TestMethod]
[RunsOnUIThread]
#if __MACOS__
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TreeView.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TreeView.cs
new file mode 100644
index 000000000000..f2348db46f0f
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TreeView.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Linq;
+using Windows.UI;
+using System.Threading.Tasks;
+using Private.Infrastructure;
+using Uno.UI.RuntimeTests.Helpers;
+using Windows.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TreeView = Microsoft.UI.Xaml.Controls.TreeView;
+using TreeViewItem = Microsoft.UI.Xaml.Controls.TreeViewItem;
+using Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls.TreeViewTests;
+using System.Collections.Generic;
+
+namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls;
+
+[TestClass]
+[RunsOnUIThread]
+public class Given_TreeView
+{
+ // Test method that create a tree of three nested items from a itemssource and that will open and close a single treeview item twice and validate that the container is still containing the same property values
+ [TestMethod]
+ public async Task When_Open_Close_Twice()
+ {
+ var SUT = new When_Open_Close_Twice();
+ TestServices.WindowHelper.WindowContent = SUT;
+
+ var root = new MyNode();
+ root.Name = "root";
+ root.Children = new List();
+ var child1 = new MyNode { Name = "Child 1" };
+ var child2 = new MyNode { Name = "Child 2" };
+ root.Children.Add(child1);
+ root.Children.Add(child2);
+
+ SUT.myTree.ItemsSource = new[] { root };
+ await TestServices.WindowHelper.WaitForIdle();
+
+ var rootNode = (TreeViewItem)SUT.FindName("root");
+ rootNode.IsExpanded = true;
+ await TestServices.WindowHelper.WaitForIdle();
+
+ var child1Node = (TreeViewItem)SUT.FindName("Child 1");
+ Assert.IsNotNull(child1Node);
+ Assert.AreEqual("Child 1", child1Node.Content);
+
+ rootNode.IsExpanded = false;
+ await TestServices.WindowHelper.WaitForIdle();
+
+ rootNode.IsExpanded = true;
+ await TestServices.WindowHelper.WaitForIdle();
+
+ var child1NodeAfter = (TreeViewItem)SUT.FindName("Child 1");
+ Assert.IsNotNull(child1NodeAfter);
+
+ Assert.AreEqual("Child 1", child1NodeAfter.Content);
+
+ var child2NodeAfter = (TreeViewItem)SUT.FindName("Child 2");
+ Assert.IsNotNull(child2NodeAfter);
+
+ Assert.AreEqual("Child 2", child2NodeAfter.Content);
+ }
+
+ private class MyNode
+ {
+ public string Name { get; set; }
+ public List Children { get; set; }
+ }
+}
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml
new file mode 100644
index 000000000000..10c620f6eb71
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml.cs
new file mode 100644
index 000000000000..9f03d997a78d
--- /dev/null
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/TreeViewTests/When_Open_Close_Twice.xaml.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls.TreeViewTests;
+
+public sealed partial class When_Open_Close_Twice : Grid
+{
+ public When_Open_Close_Twice()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs
index f95c79296aa6..4ef458bc0c0d 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs
@@ -1152,16 +1152,27 @@ internal void CleanUpContainer(global::Windows.UI.Xaml.DependencyObject element)
if (!isOwnContainer)
{
+ static void ClearPropertyWhenNoExpression(ContentControl target, DependencyProperty property)
+ {
+ // We must not clear the properties for the container if a binding expession
+ // is defined. This is a use-case present for TreeView, which generally uses TreeViewItem
+ // at the root of hierarchical templates.
+ if (target.GetBindingExpression(property) == null)
+ {
+ target.ClearValue(property);
+ }
+ }
+
// Clears value set in PrepareContainerForItemOverride
- element.ClearValue(ContentControl.ContentProperty);
+ ClearPropertyWhenNoExpression(contentControl, ContentControl.ContentProperty);
if (contentControl.ContentTemplate is { } ct && ct == ItemTemplate)
{
- contentControl.ClearValue(ContentControl.ContentTemplateProperty);
+ ClearPropertyWhenNoExpression(contentControl, ContentControl.ContentTemplateProperty);
}
else if (contentControl.ContentTemplateSelector is { } cts && cts == ItemTemplateSelector)
{
- contentControl.ClearValue(ContentControl.ContentTemplateSelectorProperty);
+ ClearPropertyWhenNoExpression(contentControl, ContentControl.ContentTemplateSelectorProperty);
}
}
}