diff --git a/src/Uno.UI.RuntimeTests/Tests/TemplatedParent/TemplatedParentTests.cs b/src/Uno.UI.RuntimeTests/Tests/TemplatedParent/TemplatedParentTests.cs index a82b2487509d..4519d56e698e 100644 --- a/src/Uno.UI.RuntimeTests/Tests/TemplatedParent/TemplatedParentTests.cs +++ b/src/Uno.UI.RuntimeTests/Tests/TemplatedParent/TemplatedParentTests.cs @@ -289,6 +289,40 @@ public async Task VisualStateGroup_TP_Inheritance() """; VerifyTree(expectations, setup, checkVSG: true); } + + [TestMethod] + public Task LateTemplateSwapping_NonContentControl() => LateTemplateSwapping(); + + [TestMethod] + public Task LateTemplateSwapping_ContentControl() => LateTemplateSwapping(); + + public async Task LateTemplateSwapping() where TControl : Control, new() + { + var templateA = XamlHelper.LoadXaml(""" + + + Template A + + + """); + var templateB = XamlHelper.LoadXaml(""" + + + Template B + + + """); + + var sut = new TControl(); + + sut.Template = templateA; + await UITestHelper.Load(sut, x => x.IsLoaded); + sut.FindFirstDescendantOrThrow("RootA"); + + sut.Template = templateB; + await UITestHelper.WaitForIdle(); + sut.FindFirstDescendantOrThrow("RootB"); + } } public partial class TemplatedParentTests // helper methods { diff --git a/src/Uno.UI/UI/Xaml/Controls/CalendarView/CalendarViewBaseItemChrome.cs b/src/Uno.UI/UI/Xaml/Controls/CalendarView/CalendarViewBaseItemChrome.cs index 97784b786a68..cd67654b44c8 100644 --- a/src/Uno.UI/UI/Xaml/Controls/CalendarView/CalendarViewBaseItemChrome.cs +++ b/src/Uno.UI/UI/Xaml/Controls/CalendarView/CalendarViewBaseItemChrome.cs @@ -112,9 +112,7 @@ private void RemoveTemplateChild() } #endif - private UIElement GetFirstChildNoAddRef() => GetFirstChild(); - - private UIElement GetFirstChild() + internal override UIElement GetFirstChild() { UIElement spFirstChild; // added in UIElement.GetFirstChild() diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs index af4264ee7983..dfbbc9259e99 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs @@ -205,7 +205,30 @@ public ControlTemplate Template private protected virtual void OnTemplateChanged(DependencyPropertyChangedEventArgs e) { -#if !UNO_HAS_ENHANCED_LIFECYCLE +#if UNO_HAS_ENHANCED_LIFECYCLE + if (e.OldValue != e.NewValue) + { + // Reset the template bindings for this control + //ClearPropertySubscriptions(); + + // When the control template property is set, we clear the visual children + var pUIElement = this.GetFirstChild(); + if (pUIElement is { }) + { + //CFrameworkTemplate* pNewTemplate = NULL; + //if (e.NewValue?.GetType() == valueObject) + //{ + // IFC(DoPointerCast(pNewTemplate, args.m_value.AsObject())); + //} + //else if (args.m_value.GetType() != valueNull) + //{ + // IFC(E_INVALIDARG); + //} + RemoveChild(pUIElement); + //IFC(GetContext()->RemoveNameScope(this, Jupiter::NameScoping::NameScopeType::TemplateNameScope)); + } + } +#else _updateTemplate = true; SetUpdateControlTemplate(); #endif diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.cs index cd0f17591dde..1f6ebb6a0918 100644 --- a/src/Uno.UI/UI/Xaml/FrameworkElement.cs +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.cs @@ -1064,7 +1064,9 @@ private protected virtual bool HasTemplateChild() return GetFirstChild() is not null; } - private UIElement/*?*/ GetFirstChild() + internal UIElement GetFirstChildNoAddRef() => GetFirstChild(); + + internal virtual UIElement/*?*/ GetFirstChild() { #if __CROSSRUNTIME__ && !__NETSTD_REFERENCE__ if (GetChildren() is { Count: > 0 } children)