fix(docking): defer container cleanup to avoid visual tree modification during layout

This commit is contained in:
2026-03-29 18:47:38 +09:00
parent d15bd22743
commit e6e38f5eea
3 changed files with 25 additions and 3 deletions

View File

@@ -142,7 +142,7 @@ public abstract class DockContainer : DockModule
/// <summary> /// <summary>
/// Checks if the container is empty and removes it from its owner if necessary. /// Checks if the container is empty and removes it from its owner if necessary.
/// </summary> /// </summary>
protected virtual void CheckCleanup() internal virtual void CheckCleanup()
{ {
if (Children.Count == 0) if (Children.Count == 0)
{ {

View File

@@ -45,7 +45,7 @@ public partial class DockPanel : DockContainer
UpdateLayoutStructure(); UpdateLayoutStructure();
} }
protected override void CheckCleanup() internal override void CheckCleanup()
{ {
base.CheckCleanup(); base.CheckCleanup();

View File

@@ -143,7 +143,6 @@ public partial class DockingLayout : Control
private void SplitGroup(DockGroup targetGroup, DockDocument doc, DockTarget target) private void SplitGroup(DockGroup targetGroup, DockDocument doc, DockTarget target)
{ {
doc.Owner?.RemoveChild(doc);
var parentPanel = targetGroup.Owner as DockPanel; var parentPanel = targetGroup.Owner as DockPanel;
var newGroup = new DockGroup(); var newGroup = new DockGroup();
@@ -272,6 +271,9 @@ public partial class DockingLayout : Control
HideHighlight(); HideHighlight();
var target = CalculateDockTarget(targetGroup, position); var target = CalculateDockTarget(targetGroup, position);
var oldOwner = doc.Owner as DockContainer;
oldOwner?.RemoveChildInternal(doc, false);
if (target == DockTarget.Center) if (target == DockTarget.Center)
{ {
if (doc.Owner == targetGroup) return; if (doc.Owner == targetGroup) return;
@@ -282,6 +284,14 @@ public partial class DockingLayout : Control
if (doc.Owner == targetGroup && targetGroup.Children.Count == 1) return; if (doc.Owner == targetGroup && targetGroup.Children.Count == 1) return;
SplitGroup(targetGroup, doc, target); 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) private DockTarget CalculateDockTarget(DockGroup group, global::Windows.Foundation.Point position)
@@ -301,9 +311,21 @@ public partial class DockingLayout : Control
internal void CreateFloatingWindow(DockDocument doc) internal void CreateFloatingWindow(DockDocument doc)
{ {
ArgumentNullException.ThrowIfNull(doc); ArgumentNullException.ThrowIfNull(doc);
var oldOwner = doc.Owner as DockContainer;
oldOwner?.RemoveChildInternal(doc, false);
var window = new FloatingWindow(doc); var window = new FloatingWindow(doc);
_floatingWindows.Add(window); _floatingWindows.Add(window);
window.Closed += (s, e) => _floatingWindows.Remove(window); window.Closed += (s, e) => _floatingWindows.Remove(window);
window.Activate(); window.Activate();
if (oldOwner != null)
{
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{
oldOwner.CheckCleanup();
});
}
} }
} }