From 3541705f5e3f9936d7be03c41af7192dc095a555 Mon Sep 17 00:00:00 2001 From: Tom Edwards Date: Thu, 26 Sep 2024 16:26:29 +0200 Subject: [PATCH] Fixed TabItem.ContentTemplate being reused for the next tab item --- src/Avalonia.Controls/TabControl.cs | 15 ++++++-- .../TabControlTests.cs | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs index cb517b293dc..6cc984f5907 100644 --- a/src/Avalonia.Controls/TabControl.cs +++ b/src/Avalonia.Controls/TabControl.cs @@ -207,10 +207,21 @@ private void UpdateSelectedContent(Control? container = null) container ??= ContainerFromIndex(SelectedIndex); if (container != null) { + if (SelectedContentTemplate != SelectContentTemplate(container.GetValue(ContentTemplateProperty))) + { + // If the value of SelectedContentTemplate is about to change, clear it first. This ensures + // that the template is not reused as soon as SelectedContent changes in the statement below + // this block, and also that controls generated from it are unloaded before SelectedContent + // (which is typically their DataContext) changes. + SelectedContentTemplate = null; + } + _selectedItemSubscriptions = new CompositeDisposable( container.GetObservable(ContentControl.ContentProperty).Subscribe(v => SelectedContent = v), - // Note how we fall back to our own ContentTemplate if the container doesn't specify one - container.GetObservable(ContentControl.ContentTemplateProperty).Subscribe(v => SelectedContentTemplate = v ?? ContentTemplate)); + container.GetObservable(ContentControl.ContentTemplateProperty).Subscribe(v => SelectedContentTemplate = SelectContentTemplate(v))); + + // Note how we fall back to our own ContentTemplate if the container doesn't specify one + IDataTemplate? SelectContentTemplate(IDataTemplate? containerTemplate) => containerTemplate ?? ContentTemplate; } } } diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs index 99e3c1db13e..4189ecd9de0 100644 --- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs @@ -405,6 +405,41 @@ public void SelectedContentTemplate_Updates_After_New_ContentTemplate() Assert.Equal("bar", Assert.IsType(target.ContentPart.Child).Tag); } + [Fact] + public void Previous_ContentTemplate_Is_Not_Reused_When_TabItem_Changes() + { + int templatesBuilt = 0; + + var target = new TabControl + { + Template = TabControlTemplate(), + Items = + { + TabItemFactory("First tab content"), + TabItemFactory("Second tab content"), + }, + }; + + var root = new TestRoot(target); + ApplyTemplate(target); + + target.SelectedIndex = 0; + target.SelectedIndex = 1; + + Assert.Equal(2, templatesBuilt); + + TabItem TabItemFactory(object content) => new() + { + Content = content, + ContentTemplate = new FuncDataTemplate((actual, ns) => + { + Assert.Equal(content, actual); + templatesBuilt++; + return new Border(); + }) + }; + } + [Fact] public void Should_Not_Propagate_DataContext_To_TabItem_Content() {