From 602dc2850f53a2fcbef0606e564c92feeb3c88a4 Mon Sep 17 00:00:00 2001 From: pavelovcharov <1357165+pavelovcharov@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:03:10 +0300 Subject: [PATCH] Fix: TabItem.TabStripPlacement is not set for new tab items (#13849) * TabItem.TabStripPlacemenet should be correctly set * fix: TabItem.TabStripPlacemenet should be correctly set * move TabItemStripPlacement assignment to PrepareContainerForItemOverride * remove excessive UpdateTabStripPlacement call on TabStripPlacementProperty.Changed --- src/Avalonia.Controls/TabControl.cs | 8 +- .../TabControlTests.cs | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs index 5b7ea7b9a5..e71a5a656b 100644 --- a/src/Avalonia.Controls/TabControl.cs +++ b/src/Avalonia.Controls/TabControl.cs @@ -73,7 +73,6 @@ namespace Avalonia.Controls { SelectionModeProperty.OverrideDefaultValue(SelectionMode.AlwaysSelected); ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); - TabStripPlacementProperty.Changed.AddClassHandler((x, e) => x.UpdateTabStripPlacement()); AffectsMeasure(TabStripPlacementProperty); SelectedItemProperty.Changed.AddClassHandler((x, e) => x.UpdateSelectedContent()); AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue(AutomationControlType.Tab); @@ -154,7 +153,7 @@ namespace Avalonia.Controls protected internal override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) { - return new TabItem { TabStripPlacement = TabStripPlacement }; + return new TabItem(); } protected internal override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) @@ -166,6 +165,11 @@ namespace Avalonia.Controls { base.PrepareContainerForItemOverride(element, item, index); + if (element is TabItem tabItem) + { + tabItem.TabStripPlacement = TabStripPlacement; + } + if (index == SelectedIndex) { UpdateSelectedContent(element); diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs index 0a409f1ef5..1ec612a85d 100644 --- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs @@ -572,6 +572,83 @@ namespace Avalonia.Controls.UnitTests Assert.Equal("Header from style", tabItem.Header); } + [Fact] + public void TabItem_TabStripPlacement_Should_Be_Correctly_Set() + { + var items = new object[] + { + "Foo", + new TabItem { Content = new TextBlock { Text = "Baz" } } + }; + + var target = new TabControl + { + Template = TabControlTemplate(), + DataContext = "Base", + ItemsSource = items + }; + + ApplyTemplate(target); + + var result = target.GetLogicalChildren() + .OfType() + .ToList(); + Assert.Collection( + result, + x => Assert.Equal(Dock.Top, x.TabStripPlacement), + x => Assert.Equal(Dock.Top, x.TabStripPlacement) + ); + + target.TabStripPlacement = Dock.Right; + result = target.GetLogicalChildren() + .OfType() + .ToList(); + Assert.Collection( + result, + x => Assert.Equal(Dock.Right, x.TabStripPlacement), + x => Assert.Equal(Dock.Right, x.TabStripPlacement) + ); + } + + [Fact] + public void TabItem_TabStripPlacement_Should_Be_Correctly_Set_For_New_Items() + { + var items = new object[] + { + "Foo", + new TabItem { Content = new TextBlock { Text = "Baz" } } + }; + + var target = new TabControl + { + Template = TabControlTemplate(), + DataContext = "Base" + }; + + ApplyTemplate(target); + + target.ItemsSource = items; + + var result = target.GetLogicalChildren() + .OfType() + .ToList(); + Assert.Collection( + result, + x => Assert.Equal(Dock.Top, x.TabStripPlacement), + x => Assert.Equal(Dock.Top, x.TabStripPlacement) + ); + + target.TabStripPlacement = Dock.Right; + result = target.GetLogicalChildren() + .OfType() + .ToList(); + Assert.Collection( + result, + x => Assert.Equal(Dock.Right, x.TabStripPlacement), + x => Assert.Equal(Dock.Right, x.TabStripPlacement) + ); + } + private static IControlTemplate TabControlTemplate() { return new FuncControlTemplate((parent, scope) =>