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

@@ -122,9 +122,13 @@ public sealed partial class DockLayout
var newWidth = grid.ColumnDefinitions[i * 2].Width;
if (!groupNode.Sizes[i].Equals(newWidth))
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newWidth;
changed = true;
// Only sync if it's a star or pixel value (not Auto)
if (newWidth.IsStar || newWidth.IsAbsolute)
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newWidth;
changed = true;
}
}
}
}
@@ -138,9 +142,12 @@ public sealed partial class DockLayout
var newHeight = grid.RowDefinitions[i * 2].Height;
if (!groupNode.Sizes[i].Equals(newHeight))
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newHeight;
changed = true;
if (newHeight.IsStar || newHeight.IsAbsolute)
{
_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
{
private long _rootPropertyToken;
private DockGroupNode? _currentRoot;
public DockWindow(object initialTabContent)
{
InitializeComponent();
@@ -21,47 +24,54 @@ 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;
void OnRootChildrenChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
_rootPropertyToken = PART_DockLayout.RegisterPropertyChangedCallback(DockLayout.RootProperty, (s, dp) =>
{
if (PART_DockLayout.Root?.Children.Count == 0)
{
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.
UnsubscribeFromRoot(_currentRoot);
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)
{
App.CreateAndShowDockWindow(e.TabContent);