diff --git a/samples/DockReactiveUICanonicalSample/App.axaml b/samples/DockReactiveUICanonicalSample/App.axaml index acc5f8ac0..88922add6 100644 --- a/samples/DockReactiveUICanonicalSample/App.axaml +++ b/samples/DockReactiveUICanonicalSample/App.axaml @@ -22,8 +22,9 @@ diff --git a/src/Dock.Avalonia/Controls/Overlays/OverlayHost.cs b/src/Dock.Avalonia/Controls/Overlays/OverlayHost.cs index e75116a61..fdebb7276 100644 --- a/src/Dock.Avalonia/Controls/Overlays/OverlayHost.cs +++ b/src/Dock.Avalonia/Controls/Overlays/OverlayHost.cs @@ -250,6 +250,14 @@ private void OnOverlayLayerPropertyChanged(object? sender, AvaloniaPropertyChang private void RebuildPipeline() { + if (Content is Control hostedContent && hostedContent.Parent is not null) + { + if (!TryDetachControl(hostedContent)) + { + return; + } + } + Child = null; var contentPresenter = new ContentPresenter @@ -268,7 +276,7 @@ private void RebuildPipeline() continue; } - if (!TryDetachOverlay(overlay)) + if (!TryDetachControl(overlay)) { continue; } @@ -315,25 +323,25 @@ private void RebuildPipeline() Child = current; } - private static bool TryDetachOverlay(Control overlay) + private static bool TryDetachControl(Control control) { - if (overlay.Parent is null) + if (control.Parent is null) { return true; } - switch (overlay.Parent) + switch (control.Parent) { case Panel panel: - panel.Children.Remove(overlay); + panel.Children.Remove(control); return true; - case Decorator decorator when ReferenceEquals(decorator.Child, overlay): + case Decorator decorator when ReferenceEquals(decorator.Child, control): decorator.Child = null; return true; - case ContentPresenter presenter when ReferenceEquals(presenter.Content, overlay): + case ContentPresenter presenter when ReferenceEquals(presenter.Content, control): presenter.Content = null; return true; - case ContentControl contentControl when ReferenceEquals(contentControl.Content, overlay): + case ContentControl contentControl when ReferenceEquals(contentControl.Content, control): contentControl.Content = null; return true; default: diff --git a/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs b/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs new file mode 100644 index 000000000..ae4a66dce --- /dev/null +++ b/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs @@ -0,0 +1,55 @@ +using System; +using Avalonia; +using Avalonia.Headless.XUnit; +using Avalonia.Styling; +using Dock.Avalonia.Controls; +using Dock.Model.Avalonia; +using Dock.Model.Controls; +using Dock.Model.Core; +using Xunit; + +namespace Dock.Avalonia.HeadlessTests; + +public class HostWindowThemeChangeTests +{ + private static IRootDock CreateLayout(Factory factory) + { + var root = factory.CreateRootDock(); + root.Factory = factory; + root.VisibleDockables = factory.CreateList(); + return root; + } + + [AvaloniaFact] + public void HostWindow_ThemeChange_DoesNotDuplicate_DockControls() + { + var app = Application.Current ?? throw new InvalidOperationException("Application is not initialized."); + var factory = new Factory(); + var layout = CreateLayout(factory); + var window = new HostWindow(); + var originalVariant = app.RequestedThemeVariant; + + try + { + window.SetLayout(layout); + window.Show(); + window.UpdateLayout(); + + Assert.Single(factory.DockControls); + Assert.Same(layout, window.Content); + + app.RequestedThemeVariant = ThemeVariant.Dark; + window.UpdateLayout(); + Assert.Single(factory.DockControls); + + app.RequestedThemeVariant = ThemeVariant.Light; + window.UpdateLayout(); + Assert.Single(factory.DockControls); + } + finally + { + window.Close(); + app.RequestedThemeVariant = originalVariant; + } + } +}