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>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.251219" /> <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="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.251219" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.2" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.2" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" /> <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 public abstract class DockContainer : DockModule
{ {
private readonly ObservableCollection<DockModule> _children = new(); private readonly ObservableCollection<DockModule> _children = new();
/// <summary>
/// Gets the collection of child modules.
/// </summary>
public ReadOnlyObservableCollection<DockModule> Children { get; } public ReadOnlyObservableCollection<DockModule> Children { get; }
protected DockContainer() protected DockContainer()
@@ -22,15 +25,27 @@ public abstract class DockContainer : DockModule
OnChildrenUpdated(); 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) public virtual void AddChild(DockModule module)
{ {
InsertChild(_children.Count, 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) public virtual void InsertChild(int index, DockModule module)
{ {
ArgumentNullException.ThrowIfNull(module); ArgumentNullException.ThrowIfNull(module);
if (index < 0 || index > _children.Count)
throw new ArgumentOutOfRangeException(nameof(index));
if (module == this) if (module == this)
throw new ArgumentException("Cannot add a container to itself.", nameof(module)); throw new ArgumentException("Cannot add a container to itself.", nameof(module));
@@ -54,6 +69,10 @@ public abstract class DockContainer : DockModule
_children.Insert(index, module); _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) public virtual void RemoveChild(DockModule module)
{ {
ArgumentNullException.ThrowIfNull(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() public void Clear()
{ {
foreach (var child in _children) foreach (var child in _children)

View File

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

View File

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

View File

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

View File

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

View File

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