fix(dock): ensure callback side-effect cleanup and improve tear-off diagnostics

This commit is contained in:
2026-03-28 17:30:50 +09:00
parent 7ac9a66110
commit 287b3b303f
3 changed files with 37 additions and 14 deletions

View File

@@ -59,9 +59,23 @@ public partial class App : Application
internal static void CreateAndShowDockWindow(object tabContent) internal static void CreateAndShowDockWindow(object tabContent)
{ {
var newWindow = new Ghost.Editor.View.Windows.DockWindow(tabContent); var newWindow = new Ghost.Editor.View.Windows.DockWindow(tabContent);
try
{
AddSecondaryWindow(newWindow); AddSecondaryWindow(newWindow);
newWindow.Activate(); 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 internal IHost Host
{ {

View File

@@ -433,14 +433,15 @@ public sealed partial class DockLayout : Control
{ {
// Validate that the item actually belongs to this source node before attempting tear-off // Validate that the item actually belongs to this source node before attempting tear-off
if (sourceNode.Items.Contains(args.Item)) if (sourceNode.Items.Contains(args.Item))
{
var result = TabTearOffService.TryTearOffTab(sourceNode.Items, args.Item, (tab) =>
{ {
if (TabTornOff == null) if (TabTornOff == null)
{ {
throw new InvalidOperationException("No tear-off handler attached."); Logger.LogWarning("Tab dropped outside but no TabTornOff subscribers found.");
return;
} }
var result = TabTearOffService.TryTearOffTab(sourceNode.Items, args.Item, (tab) =>
{
// Raise event to let the host handle window creation // Raise event to let the host handle window creation
TabTornOff.Invoke(this, new TabTornOffEventArgs(tab, sourceNode)); TabTornOff.Invoke(this, new TabTornOffEventArgs(tab, sourceNode));
}, sourceNode); }, sourceNode);

View File

@@ -42,7 +42,9 @@ internal sealed partial class EngineEditorWindow : WindowEx
private void OnTabDroppedOutside(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDroppedOutsideEventArgs args) 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 // 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)
{
if (list.Contains(args.Item))
{ {
var result = TabTearOffService.TryTearOffTab(list, args.Item, (tab) => var result = TabTearOffService.TryTearOffTab(list, args.Item, (tab) =>
{ {
@@ -54,6 +56,12 @@ internal sealed partial class EngineEditorWindow : WindowEx
Logger.LogWarning($"Tab tear-off failed: {result.Message}"); Logger.LogWarning($"Tab tear-off failed: {result.Message}");
} }
} }
else
{
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}).");
}
}
} }
private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)