Skip to content

Commit

Permalink
Fixed TabItem.ContentTemplate being reused for the next tab item (#17141
Browse files Browse the repository at this point in the history
)
  • Loading branch information
TomEdwardsEnscape authored Sep 27, 2024
1 parent 432fbe8 commit 1e34a78
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/Avalonia.Controls/TabControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions tests/Avalonia.Controls.UnitTests/TabControlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,41 @@ public void SelectedContentTemplate_Updates_After_New_ContentTemplate()
Assert.Equal("bar", Assert.IsType<TextBlock>(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<object>((actual, ns) =>
{
Assert.Equal(content, actual);
templatesBuilt++;
return new Border();
})
};
}

[Fact]
public void Should_Not_Propagate_DataContext_To_TabItem_Content()
{
Expand Down

0 comments on commit 1e34a78

Please sign in to comment.