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;
/// <summary>
/// Defines the possible dock positions for a drop operation.
/// </summary>
internal enum DockPosition
{
Center,
Top,
Bottom,
Left,
Right,
None
}
/// <summary>
/// Helper class for docking-related calculations.
/// </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

@@ -121,6 +121,9 @@ public sealed partial class DockLayout
{
var newWidth = grid.ColumnDefinitions[i * 2].Width;
if (!groupNode.Sizes[i].Equals(newWidth))
{
// Only sync if it's a star or pixel value (not Auto)
if (newWidth.IsStar || newWidth.IsAbsolute)
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newWidth;
@@ -129,6 +132,7 @@ public sealed partial class DockLayout
}
}
}
}
else
{
for (int i = 0; i < groupNode.Children.Count; i++)
@@ -137,6 +141,8 @@ public sealed partial class DockLayout
{
var newHeight = grid.RowDefinitions[i * 2].Height;
if (!groupNode.Sizes[i].Equals(newHeight))
{
if (newHeight.IsStar || newHeight.IsAbsolute)
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newHeight;
@@ -145,6 +151,7 @@ public sealed partial class DockLayout
}
}
}
}
if (changed)
{

View File

@@ -7,6 +7,9 @@ namespace Ghost.Editor.View.Windows;
internal sealed partial class DockWindow : WindowEx
{
private long _rootPropertyToken;
private DockGroupNode? _currentRoot;
public DockWindow(object initialTabContent)
{
InitializeComponent();
@@ -21,14 +24,30 @@ internal sealed partial class DockWindow : WindowEx
PART_DockLayout.TabTornOff += OnTabTornOff;
RegisterCloseHandler();
this.Closed += (s, e) =>
{
if (_rootPropertyToken != 0)
{
PART_DockLayout.UnregisterPropertyChangedCallback(DockLayout.RootProperty, _rootPropertyToken);
_rootPropertyToken = 0;
}
UnsubscribeFromRoot(_currentRoot);
};
}
private void RegisterCloseHandler()
{
// Subscribe to Root changes to ensure we always track the current tree
var rootProperty = DockLayout.RootProperty;
_rootPropertyToken = PART_DockLayout.RegisterPropertyChangedCallback(DockLayout.RootProperty, (s, dp) =>
{
UnsubscribeFromRoot(_currentRoot);
SubscribeToRoot(PART_DockLayout.Root);
});
void OnRootChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
SubscribeToRoot(PART_DockLayout.Root);
}
private void OnRootChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (PART_DockLayout.Root?.Children.Count == 0)
{
@@ -36,15 +55,16 @@ internal sealed partial class DockWindow : WindowEx
}
}
void SubscribeToRoot(DockGroupNode? root)
private void SubscribeToRoot(DockGroupNode? root)
{
if (root != null)
_currentRoot = root;
if (_currentRoot != null)
{
((System.Collections.Specialized.INotifyCollectionChanged)root.Children).CollectionChanged += OnRootChildrenChanged;
((System.Collections.Specialized.INotifyCollectionChanged)_currentRoot.Children).CollectionChanged += OnRootChildrenChanged;
}
}
void UnsubscribeFromRoot(DockGroupNode? root)
private void UnsubscribeFromRoot(DockGroupNode? root)
{
if (root != null)
{
@@ -52,16 +72,6 @@ internal sealed partial class DockWindow : WindowEx
}
}
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);
}
private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
{
App.CreateAndShowDockWindow(e.TabContent);