diff --git a/src/Editor/Ghost.Editor/App.xaml.cs b/src/Editor/Ghost.Editor/App.xaml.cs index cbc36df..be02cd9 100644 --- a/src/Editor/Ghost.Editor/App.xaml.cs +++ b/src/Editor/Ghost.Editor/App.xaml.cs @@ -59,8 +59,22 @@ public partial class App : Application internal static void CreateAndShowDockWindow(object tabContent) { var newWindow = new Ghost.Editor.View.Windows.DockWindow(tabContent); - AddSecondaryWindow(newWindow); - newWindow.Activate(); + try + { + AddSecondaryWindow(newWindow); + newWindow.Activate(); + } + catch (Exception ex) + { + // Cleanup partially created window + if (Current is App app) + { + app._secondaryWindows.Remove(newWindow); + } + newWindow.Close(); + Logger.LogError(ex); + throw; + } } internal IHost Host diff --git a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs index 3546cc6..8375acf 100644 --- a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs +++ b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs @@ -434,13 +434,14 @@ public sealed partial class DockLayout : Control // Validate that the item actually belongs to this source node before attempting tear-off if (sourceNode.Items.Contains(args.Item)) { + if (TabTornOff == null) + { + Logger.LogWarning("Tab dropped outside but no TabTornOff subscribers found."); + return; + } + var result = TabTearOffService.TryTearOffTab(sourceNode.Items, args.Item, (tab) => { - if (TabTornOff == null) - { - throw new InvalidOperationException("No tear-off handler attached."); - } - // Raise event to let the host handle window creation TabTornOff.Invoke(this, new TabTornOffEventArgs(tab, sourceNode)); }, sourceNode); diff --git a/src/Editor/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs b/src/Editor/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs index 6192c45..d613507 100644 --- a/src/Editor/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs +++ b/src/Editor/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs @@ -42,16 +42,24 @@ internal sealed partial class EngineEditorWindow : WindowEx private void OnTabDroppedOutside(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDroppedOutsideEventArgs args) { // For static tabs in EngineEditorWindow, we remove the item from TabItems - if (sender.TabItems is System.Collections.IList list && list.Contains(args.Item)) + if (sender.TabItems is System.Collections.IList list) { - var result = TabTearOffService.TryTearOffTab(list, args.Item, (tab) => + if (list.Contains(args.Item)) { - App.CreateAndShowDockWindow(tab); - }, sender); - - if (!result.IsSuccess) + var result = TabTearOffService.TryTearOffTab(list, args.Item, (tab) => + { + App.CreateAndShowDockWindow(tab); + }, sender); + + if (!result.IsSuccess) + { + Logger.LogWarning($"Tab tear-off failed: {result.Message}"); + } + } + else { - Logger.LogWarning($"Tab tear-off failed: {result.Message}"); + string itemInfo = args.Item is FrameworkElement fe ? fe.GetType().Name : args.Item?.ToString() ?? "unknown"; + Logger.LogWarning($"OnTabDroppedOutside: Item '{itemInfo}' not found in source TabView (Items count: {list.Count})."); } } }