fix(docking): improve structural integrity and add null validation
This commit is contained in:
@@ -9,6 +9,7 @@ namespace Ghost.Editor.View.Controls.Docking;
|
|||||||
public abstract class DockContainer : DockModule
|
public abstract class DockContainer : DockModule
|
||||||
{
|
{
|
||||||
private readonly ObservableCollection<DockModule> _children = new();
|
private readonly ObservableCollection<DockModule> _children = new();
|
||||||
|
protected bool _isCleaningUp;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of child modules.
|
/// Gets the collection of child modules.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,9 +82,42 @@ public abstract class DockContainer : DockModule
|
|||||||
{
|
{
|
||||||
module.Owner = null;
|
module.Owner = null;
|
||||||
module.Root = null;
|
module.Root = null;
|
||||||
|
if (!_isCleaningUp)
|
||||||
|
{
|
||||||
CheckCleanup();
|
CheckCleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ReplaceChild(DockModule oldChild, DockModule newChild)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(oldChild);
|
||||||
|
ArgumentNullException.ThrowIfNull(newChild);
|
||||||
|
int index = _children.IndexOf(oldChild);
|
||||||
|
if (index < 0) throw new ArgumentException("oldChild not found");
|
||||||
|
|
||||||
|
// Detach newChild from its current owner if any
|
||||||
|
newChild.Owner?.RemoveChild(newChild);
|
||||||
|
|
||||||
|
// Remove oldChild without triggering cleanup
|
||||||
|
_isCleaningUp = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_children.RemoveAt(index);
|
||||||
|
oldChild.Owner = null;
|
||||||
|
oldChild.Root = null;
|
||||||
|
|
||||||
|
newChild.Owner = this;
|
||||||
|
newChild.Root = Root;
|
||||||
|
_children.Insert(index, newChild);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isCleaningUp = false;
|
||||||
|
}
|
||||||
|
OnChildrenUpdated();
|
||||||
|
CheckCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void CheckCleanup()
|
protected virtual void CheckCleanup()
|
||||||
{
|
{
|
||||||
@@ -104,6 +138,10 @@ public abstract class DockContainer : DockModule
|
|||||||
child.Root = null;
|
child.Root = null;
|
||||||
}
|
}
|
||||||
_children.Clear();
|
_children.Clear();
|
||||||
|
if (!_isCleaningUp)
|
||||||
|
{
|
||||||
|
CheckCleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRootChanged()
|
protected override void OnRootChanged()
|
||||||
|
|||||||
@@ -57,10 +57,12 @@ public class DockPanel : DockContainer
|
|||||||
|
|
||||||
if (owner != null)
|
if (owner != null)
|
||||||
{
|
{
|
||||||
int index = owner.Children.IndexOf(this);
|
owner.ReplaceChild(this, child);
|
||||||
owner.RemoveChild(this);
|
}
|
||||||
child.Detach();
|
else if (Root != null && Root.RootPanel == this)
|
||||||
owner.InsertChild(index, child);
|
{
|
||||||
|
// If this is the root panel, we can't easily replace it if the child is a DockGroup,
|
||||||
|
// because RootPanel must be a DockPanel. So we just leave it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ public class DockingLayout : Control
|
|||||||
/// <param name="targetGroup">The target group to add the document to. If null, a suitable group will be found or created.</param>
|
/// <param name="targetGroup">The target group to add the document to. If null, a suitable group will be found or created.</param>
|
||||||
public void AddDocument(DockDocument document, DockTarget target, DockGroup? targetGroup = null)
|
public void AddDocument(DockDocument document, DockTarget target, DockGroup? targetGroup = null)
|
||||||
{
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(document);
|
||||||
|
|
||||||
if (targetGroup != null && targetGroup.Root != this)
|
if (targetGroup != null && targetGroup.Root != this)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("targetGroup does not belong to this DockingLayout");
|
throw new ArgumentException("targetGroup does not belong to this DockingLayout");
|
||||||
|
|||||||
Reference in New Issue
Block a user