fix(dock): improve window lifecycle, size sync performance, and code style

This commit is contained in:
2026-03-28 19:00:09 +09:00
parent 71abd60a75
commit 975c359bf4
4 changed files with 67 additions and 49 deletions

View File

@@ -1,18 +1,5 @@
namespace Ghost.Editor.Core.Controls.Internal.Docking; namespace Ghost.Editor.Core.Controls.Internal.Docking;
/// <summary>
/// Defines the possible dock positions for a drop operation.
/// </summary>
internal enum DockPosition
{
Center,
Top,
Bottom,
Left,
Right,
None
}
/// <summary> /// <summary>
/// Helper class for docking-related calculations. /// Helper class for docking-related calculations.
/// </summary> /// </summary>

View File

@@ -0,0 +1,14 @@
namespace Ghost.Editor.Core.Controls.Internal.Docking;
/// <summary>
/// Defines the possible dock positions for a drop operation.
/// </summary>
internal enum DockPosition
{
Center,
Top,
Bottom,
Left,
Right,
None
}

View File

@@ -122,9 +122,13 @@ public sealed partial class DockLayout
var newWidth = grid.ColumnDefinitions[i * 2].Width; var newWidth = grid.ColumnDefinitions[i * 2].Width;
if (!groupNode.Sizes[i].Equals(newWidth)) if (!groupNode.Sizes[i].Equals(newWidth))
{ {
_isSyncingSizes = true; // Only sync if it's a star or pixel value (not Auto)
groupNode.Sizes[i] = newWidth; if (newWidth.IsStar || newWidth.IsAbsolute)
changed = true; {
_isSyncingSizes = true;
groupNode.Sizes[i] = newWidth;
changed = true;
}
} }
} }
} }
@@ -138,9 +142,12 @@ public sealed partial class DockLayout
var newHeight = grid.RowDefinitions[i * 2].Height; var newHeight = grid.RowDefinitions[i * 2].Height;
if (!groupNode.Sizes[i].Equals(newHeight)) if (!groupNode.Sizes[i].Equals(newHeight))
{ {
_isSyncingSizes = true; if (newHeight.IsStar || newHeight.IsAbsolute)
groupNode.Sizes[i] = newHeight; {
changed = true; _isSyncingSizes = true;
groupNode.Sizes[i] = newHeight;
changed = true;
}
} }
} }
} }

View File

@@ -7,6 +7,9 @@ namespace Ghost.Editor.View.Windows;
internal sealed partial class DockWindow : WindowEx internal sealed partial class DockWindow : WindowEx
{ {
private long _rootPropertyToken;
private DockGroupNode? _currentRoot;
public DockWindow(object initialTabContent) public DockWindow(object initialTabContent)
{ {
InitializeComponent(); InitializeComponent();
@@ -21,47 +24,54 @@ internal sealed partial class DockWindow : WindowEx
PART_DockLayout.TabTornOff += OnTabTornOff; PART_DockLayout.TabTornOff += OnTabTornOff;
RegisterCloseHandler(); RegisterCloseHandler();
this.Closed += (s, e) =>
{
if (_rootPropertyToken != 0)
{
PART_DockLayout.UnregisterPropertyChangedCallback(DockLayout.RootProperty, _rootPropertyToken);
_rootPropertyToken = 0;
}
UnsubscribeFromRoot(_currentRoot);
};
} }
private void RegisterCloseHandler() private void RegisterCloseHandler()
{ {
// Subscribe to Root changes to ensure we always track the current tree _rootPropertyToken = PART_DockLayout.RegisterPropertyChangedCallback(DockLayout.RootProperty, (s, dp) =>
var rootProperty = DockLayout.RootProperty;
void OnRootChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{ {
if (PART_DockLayout.Root?.Children.Count == 0) UnsubscribeFromRoot(_currentRoot);
{
this.Close();
}
}
void SubscribeToRoot(DockGroupNode? root)
{
if (root != null)
{
((System.Collections.Specialized.INotifyCollectionChanged)root.Children).CollectionChanged += OnRootChildrenChanged;
}
}
void UnsubscribeFromRoot(DockGroupNode? root)
{
if (root != null)
{
((System.Collections.Specialized.INotifyCollectionChanged)root.Children).CollectionChanged -= OnRootChildrenChanged;
}
}
PART_DockLayout.RegisterPropertyChangedCallback(DockLayout.RootProperty, (s, dp) =>
{
// This is a bit tricky since we don't have the old value easily here in RegisterPropertyChangedCallback
// But for DockWindow, the root is usually set once.
SubscribeToRoot(PART_DockLayout.Root); SubscribeToRoot(PART_DockLayout.Root);
}); });
SubscribeToRoot(PART_DockLayout.Root); SubscribeToRoot(PART_DockLayout.Root);
} }
private void OnRootChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (PART_DockLayout.Root?.Children.Count == 0)
{
this.Close();
}
}
private void SubscribeToRoot(DockGroupNode? root)
{
_currentRoot = root;
if (_currentRoot != null)
{
((System.Collections.Specialized.INotifyCollectionChanged)_currentRoot.Children).CollectionChanged += OnRootChildrenChanged;
}
}
private void UnsubscribeFromRoot(DockGroupNode? root)
{
if (root != null)
{
((System.Collections.Specialized.INotifyCollectionChanged)root.Children).CollectionChanged -= OnRootChildrenChanged;
}
}
private void OnTabTornOff(object? sender, TabTornOffEventArgs e) private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
{ {
App.CreateAndShowDockWindow(e.TabContent); App.CreateAndShowDockWindow(e.TabContent);