fix(docking): address code quality issues and improve docking robustness

This commit is contained in:
2026-03-28 22:32:57 +09:00
parent 55eb240de6
commit e5aa328576
7 changed files with 46 additions and 8 deletions

View File

@@ -36,6 +36,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Sizers" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.251219" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.2" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />

View File

@@ -9,6 +9,9 @@ namespace Ghost.Editor.View.Controls.Docking;
public abstract class DockContainer : DockModule
{
private readonly ObservableCollection<DockModule> _children = new();
/// <summary>
/// Gets the collection of child modules.
/// </summary>
public ReadOnlyObservableCollection<DockModule> Children { get; }
protected DockContainer()
@@ -22,15 +25,27 @@ public abstract class DockContainer : DockModule
OnChildrenUpdated();
}
/// <summary>
/// Adds a child module to the end of the container.
/// </summary>
/// <param name="module">The module to add.</param>
public virtual void AddChild(DockModule module)
{
InsertChild(_children.Count, module);
}
/// <summary>
/// Inserts a child module at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which the module should be inserted.</param>
/// <param name="module">The module to insert.</param>
public virtual void InsertChild(int index, DockModule module)
{
ArgumentNullException.ThrowIfNull(module);
if (index < 0 || index > _children.Count)
throw new ArgumentOutOfRangeException(nameof(index));
if (module == this)
throw new ArgumentException("Cannot add a container to itself.", nameof(module));
@@ -54,6 +69,10 @@ public abstract class DockContainer : DockModule
_children.Insert(index, module);
}
/// <summary>
/// Removes a child module from the container.
/// </summary>
/// <param name="module">The module to remove.</param>
public virtual void RemoveChild(DockModule module)
{
ArgumentNullException.ThrowIfNull(module);
@@ -74,6 +93,9 @@ public abstract class DockContainer : DockModule
}
}
/// <summary>
/// Removes all child modules from the container.
/// </summary>
public void Clear()
{
foreach (var child in _children)

View File

@@ -11,12 +11,18 @@ public partial class DockDocument : DockModule
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
nameof(Content), typeof(object), typeof(DockDocument), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the title of the document.
/// </summary>
public string? Title
{
get => (string?)GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
/// <summary>
/// Gets or sets the content of the document.
/// </summary>
public object? Content
{
get => GetValue(ContentProperty);

View File

@@ -157,5 +157,9 @@ public partial class DockGroup : DockContainer
{
_tabView.SelectedItem = newSelectedItem;
}
else
{
_tabView.SelectedItem = _tabView.TabItems.FirstOrDefault();
}
}
}

View File

@@ -7,6 +7,9 @@ namespace Ghost.Editor.View.Controls.Docking;
/// </summary>
public abstract class DockModule : Control
{
/// <summary>
/// Gets the container that owns this module.
/// </summary>
public DockContainer? Owner { get; internal set; }
private DockingLayout? _root;
@@ -29,6 +32,9 @@ public abstract class DockModule : Control
protected virtual void OnRootChanged() { }
/// <summary>
/// Detaches this module from its current owner.
/// </summary>
public void Detach()
{
Owner?.RemoveChild(this);

View File

@@ -16,6 +16,9 @@ public class DockPanel : DockContainer
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
nameof(Orientation), typeof(Orientation), typeof(DockPanel), new PropertyMetadata(Orientation.Horizontal, OnOrientationChanged));
/// <summary>
/// Gets or sets the orientation of the panel.
/// </summary>
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
@@ -89,7 +92,7 @@ public class DockPanel : DockContainer
if (i < Children.Count - 1)
{
_grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
var splitter = new CommunityToolkit.WinUI.Controls.GridSplitter { ResizeDirection = CommunityToolkit.WinUI.Controls.GridSplitter.GridResizeDirection.Columns, Width = SPLITTER_THICKNESS };
var splitter = new GridSplitter { ResizeDirection = GridSplitter.GridResizeDirection.Columns, Width = SPLITTER_THICKNESS };
Grid.SetColumn(splitter, i * 2 + 1);
_grid.Children.Add(splitter);
}
@@ -107,7 +110,7 @@ public class DockPanel : DockContainer
if (i < Children.Count - 1)
{
_grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
var splitter = new CommunityToolkit.WinUI.Controls.GridSplitter { ResizeDirection = CommunityToolkit.WinUI.Controls.GridSplitter.GridResizeDirection.Rows, Height = SPLITTER_THICKNESS };
var splitter = new GridSplitter { ResizeDirection = GridSplitter.GridResizeDirection.Rows, Height = SPLITTER_THICKNESS };
Grid.SetRow(splitter, i * 2 + 1);
_grid.Children.Add(splitter);
}

View File

@@ -147,8 +147,8 @@ public class DockingLayout : Control
else
{
// Different orientation, need a new sub-panel
targetGroup.Detach();
var newPanel = new DockPanel { Orientation = orientation };
parentPanel.InsertChild(index, newPanel);
if (target == DockTarget.Left || target == DockTarget.Top)
{
@@ -160,8 +160,6 @@ public class DockingLayout : Control
newPanel.AddChild(targetGroup);
newPanel.AddChild(newGroup);
}
parentPanel.InsertChild(index, newPanel);
}
}
}
@@ -228,10 +226,9 @@ public class DockingLayout : Control
HideHighlight();
var target = CalculateDockTarget(targetGroup, position);
doc.Detach();
if (target == DockTarget.Center)
{
if (doc.Owner == targetGroup) return;
targetGroup.AddChild(doc);
}
else
@@ -256,7 +253,6 @@ public class DockingLayout : Control
internal void CreateFloatingWindow(DockDocument doc)
{
doc.Detach();
// To be implemented in Task 6
}
}