From 8c136709ff62c49933d7aef380cdc39e5bfc3e1e Mon Sep 17 00:00:00 2001 From: Misaki Date: Sat, 28 Mar 2026 15:56:53 +0900 Subject: [PATCH] fix(dock): decouple DockLayout from App and fix multi-window shutdown --- src/Editor/Ghost.Editor/App.xaml.cs | 14 +++++++++++++- .../Ghost.Editor/View/Controls/DockLayout.cs | 14 ++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Editor/Ghost.Editor/App.xaml.cs b/src/Editor/Ghost.Editor/App.xaml.cs index 5e0282b..ca6f91a 100644 --- a/src/Editor/Ghost.Editor/App.xaml.cs +++ b/src/Editor/Ghost.Editor/App.xaml.cs @@ -47,6 +47,10 @@ public partial class App : Application app._secondaryWindows.Add(window); window.Closed += (s, e) => app._secondaryWindows.Remove(window); } + else + { + throw new InvalidOperationException("App instance is not available."); + } } internal IHost Host @@ -151,6 +155,14 @@ public partial class App : Application { try { + // Close all secondary windows when the primary window closes + var secondaryWindows = _secondaryWindows.ToArray(); + foreach (var window in secondaryWindows) + { + window.Close(); + } + _secondaryWindows.Clear(); + Host.StopAsync().GetAwaiter().GetResult(); Host.Dispose(); @@ -169,4 +181,4 @@ public partial class App : Application Debugger.BreakForUserUnhandledException(e.Exception); #endif } -} \ No newline at end of file +} diff --git a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs index 6d74a72..a349551 100644 --- a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs +++ b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs @@ -295,6 +295,8 @@ public sealed partial class DockLayout : Control return tabView; } + public event EventHandler? TabTornOff; + private void TabView_TabDroppedOutside(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDroppedOutsideEventArgs args) { if (_sourceNode != null && _draggedItem != null) @@ -304,16 +306,20 @@ public sealed partial class DockLayout : Control { DockMutationEngine.CleanupEmptyNodes(_sourceNode); - // Create new window and register it with App to prevent GC - var newWindow = new Ghost.Editor.View.Windows.DockWindow(_draggedItem); - App.AddSecondaryWindow(newWindow); - newWindow.Activate(); + // Raise event to let the host handle window creation + TabTornOff?.Invoke(this, new TabTornOffEventArgs(_draggedItem)); } ClearDragOperationState(); } } + public class TabTornOffEventArgs : EventArgs + { + public object TabContent { get; } + public TabTornOffEventArgs(object tabContent) => TabContent = tabContent; + } + private object? _draggedItem; private DockPanelNode? _sourceNode; private DockPosition _currentDropPosition = DockPosition.None;