From f9a226f38affd1f0292e9c2b7d2ae0541a945e21 Mon Sep 17 00:00:00 2001 From: Dirkster99 Date: Wed, 1 Apr 2020 20:57:49 +0200 Subject: [PATCH] Fixing exceptions in Drag LayoutAnchoreables to DocumentPane https://github.com/Dirkster99/AvalonDock/issues/71#issuecomment-567634746 --- .../AvalonDock/Layout/LayoutAnchorable.cs | 2 +- .../AvalonDock/Layout/LayoutContent.cs | 11 ++++++++-- .../AvalonDock/Layout/LayoutRoot.cs | 22 ++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/source/Components/AvalonDock/Layout/LayoutAnchorable.cs b/source/Components/AvalonDock/Layout/LayoutAnchorable.cs index 74481b81..3aabc49e 100644 --- a/source/Components/AvalonDock/Layout/LayoutAnchorable.cs +++ b/source/Components/AvalonDock/Layout/LayoutAnchorable.cs @@ -323,7 +323,7 @@ public void Show() { var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount) - previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this); + previousContainerAsLayoutGroup.InsertChildAt((PreviousContainerIndex < 0 ? 0 : PreviousContainerIndex), this); else previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this); diff --git a/source/Components/AvalonDock/Layout/LayoutContent.cs b/source/Components/AvalonDock/Layout/LayoutContent.cs index fc8e3456..0121c7dc 100644 --- a/source/Components/AvalonDock/Layout/LayoutContent.cs +++ b/source/Components/AvalonDock/Layout/LayoutContent.cs @@ -693,18 +693,25 @@ internal void CloseInternal() var root = Root; var parentAsContainer = Parent; + // Determine if this pane is the only DocumentPane present in the layout of the main window (not floating) + // then it will be skipped for removal in GarbageCollection (even if it is empty) + bool isParentRemoved = Root.Manager.Layout.IsParentRemoved(Parent); + if (PreviousContainer == null) { var parentAsGroup = Parent as ILayoutGroup; PreviousContainer = parentAsContainer; PreviousContainerIndex = parentAsGroup.IndexOfChild(this); - if (parentAsGroup is ILayoutPaneSerializable layoutPaneSerializable) + if (isParentRemoved == false && parentAsGroup is ILayoutPaneSerializable layoutPaneSerializable) { PreviousContainerId = layoutPaneSerializable.Id; - // This parentAsGroup will be removed in the GarbageCollection below + + // Check whether this parentAsGroup will be removed in the GarbageCollection below if (parentAsGroup.Children.Count() == 1 && parentAsGroup.Parent != null && Root.Manager != null) { + // move LayoutContent up in the layout tree by setting PreviousContainer to it's grandparent + // (a LayoutPanel) by assumption that the parent will be garbage collected below. Parent = Root.Manager.Layout; PreviousContainer = parentAsGroup.Parent; PreviousContainerIndex = -1; diff --git a/source/Components/AvalonDock/Layout/LayoutRoot.cs b/source/Components/AvalonDock/Layout/LayoutRoot.cs index 402cede2..ac578059 100644 --- a/source/Components/AvalonDock/Layout/LayoutRoot.cs +++ b/source/Components/AvalonDock/Layout/LayoutRoot.cs @@ -376,9 +376,7 @@ public void CollectGarbage() } //...if this pane is the only documentpane present in the layout of the main window (not floating) then skip it - if (emptyPane is LayoutDocumentPane && - emptyPane.FindParent() == null && - this.Descendents().OfType().Count(c => c != emptyPane && c.FindParent() == null) == 0) + if (IsParentRemoved(emptyPane)) continue; //...if this empty pane is not referenced by anyone, then remove it from its parent container @@ -620,6 +618,24 @@ void IXmlSerializable.WriteXml(XmlWriter writer) } writer.WriteEndElement(); } + + /// + /// Determine if the parent pane is the only DocumentPane present in the layout of the main window (not floating) + /// then it will be skipped for removal in GarbageCollection (even if it is empty). + /// + /// Otherwise, an empty pane will be removed in the LayoutRoot.GarbageCollection() which means that PreviousContainer + /// must be adjusted before items are removed from their parent pane. + /// + /// + /// + internal bool IsParentRemoved(ILayoutContainer parent) + { + if (parent == null) return false; + + return (parent is LayoutDocumentPane && + parent.FindParent() == null && + this.Descendents().OfType().Count(c => c != parent && c.FindParent() == null) == 0); + } #endregion IXmlSerializable interface members #endregion Public Methods