From e6e38f5eea1811092eac4d4ef149650f3860838e Mon Sep 17 00:00:00 2001 From: Misaki Date: Sun, 29 Mar 2026 18:47:38 +0900 Subject: [PATCH] fix(docking): defer container cleanup to avoid visual tree modification during layout --- .../View/Controls/Docking/DockContainer.cs | 2 +- .../View/Controls/Docking/DockPanel.cs | 2 +- .../View/Controls/Docking/DockingLayout.cs | 24 ++++++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Editor/Ghost.Editor/View/Controls/Docking/DockContainer.cs b/src/Editor/Ghost.Editor/View/Controls/Docking/DockContainer.cs index dacf2e5..37721d8 100644 --- a/src/Editor/Ghost.Editor/View/Controls/Docking/DockContainer.cs +++ b/src/Editor/Ghost.Editor/View/Controls/Docking/DockContainer.cs @@ -142,7 +142,7 @@ public abstract class DockContainer : DockModule /// /// Checks if the container is empty and removes it from its owner if necessary. /// - protected virtual void CheckCleanup() + internal virtual void CheckCleanup() { if (Children.Count == 0) { diff --git a/src/Editor/Ghost.Editor/View/Controls/Docking/DockPanel.cs b/src/Editor/Ghost.Editor/View/Controls/Docking/DockPanel.cs index 183a39a..623cb9a 100644 --- a/src/Editor/Ghost.Editor/View/Controls/Docking/DockPanel.cs +++ b/src/Editor/Ghost.Editor/View/Controls/Docking/DockPanel.cs @@ -45,7 +45,7 @@ public partial class DockPanel : DockContainer UpdateLayoutStructure(); } - protected override void CheckCleanup() + internal override void CheckCleanup() { base.CheckCleanup(); diff --git a/src/Editor/Ghost.Editor/View/Controls/Docking/DockingLayout.cs b/src/Editor/Ghost.Editor/View/Controls/Docking/DockingLayout.cs index f94e52b..130d3ea 100644 --- a/src/Editor/Ghost.Editor/View/Controls/Docking/DockingLayout.cs +++ b/src/Editor/Ghost.Editor/View/Controls/Docking/DockingLayout.cs @@ -143,7 +143,6 @@ public partial class DockingLayout : Control private void SplitGroup(DockGroup targetGroup, DockDocument doc, DockTarget target) { - doc.Owner?.RemoveChild(doc); var parentPanel = targetGroup.Owner as DockPanel; var newGroup = new DockGroup(); @@ -272,6 +271,9 @@ public partial class DockingLayout : Control HideHighlight(); var target = CalculateDockTarget(targetGroup, position); + var oldOwner = doc.Owner as DockContainer; + oldOwner?.RemoveChildInternal(doc, false); + if (target == DockTarget.Center) { if (doc.Owner == targetGroup) return; @@ -282,6 +284,14 @@ public partial class DockingLayout : Control if (doc.Owner == targetGroup && targetGroup.Children.Count == 1) return; SplitGroup(targetGroup, doc, target); } + + if (oldOwner != null) + { + DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + oldOwner.CheckCleanup(); + }); + } } private DockTarget CalculateDockTarget(DockGroup group, global::Windows.Foundation.Point position) @@ -301,9 +311,21 @@ public partial class DockingLayout : Control internal void CreateFloatingWindow(DockDocument doc) { ArgumentNullException.ThrowIfNull(doc); + + var oldOwner = doc.Owner as DockContainer; + oldOwner?.RemoveChildInternal(doc, false); + var window = new FloatingWindow(doc); _floatingWindows.Add(window); window.Closed += (s, e) => _floatingWindows.Remove(window); window.Activate(); + + if (oldOwner != null) + { + DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => + { + oldOwner.CheckCleanup(); + }); + } } }