fix(dock): ensure persistent sizing capture and improve window close logic

This commit is contained in:
2026-03-28 18:48:00 +09:00
parent 777c4ef31d
commit 71abd60a75
4 changed files with 72 additions and 6 deletions

View File

@@ -101,21 +101,31 @@ public sealed partial class DockLayout
} }
// Capture size changes to persist back to model // Capture size changes to persist back to model
grid.SizeChanged += (s, e) => SyncSizesToModel(groupNode, grid); grid.LayoutUpdated += (s, e) => SyncSizesToModel(groupNode, grid);
return grid; return grid;
} }
private void SyncSizesToModel(DockGroupNode groupNode, Grid grid) private void SyncSizesToModel(DockGroupNode groupNode, Grid grid)
{ {
if (_isSyncingSizes) return;
bool isHorizontal = groupNode.Orientation == Orientation.Horizontal; bool isHorizontal = groupNode.Orientation == Orientation.Horizontal;
bool changed = false;
if (isHorizontal) if (isHorizontal)
{ {
for (int i = 0; i < groupNode.Children.Count; i++) for (int i = 0; i < groupNode.Children.Count; i++)
{ {
if (i < groupNode.Sizes.Count && i * 2 < grid.ColumnDefinitions.Count) if (i < groupNode.Sizes.Count && i * 2 < grid.ColumnDefinitions.Count)
{ {
groupNode.Sizes[i] = grid.ColumnDefinitions[i * 2].Width; var newWidth = grid.ColumnDefinitions[i * 2].Width;
if (!groupNode.Sizes[i].Equals(newWidth))
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newWidth;
changed = true;
}
} }
} }
} }
@@ -125,12 +135,23 @@ public sealed partial class DockLayout
{ {
if (i < groupNode.Sizes.Count && i * 2 < grid.RowDefinitions.Count) if (i < groupNode.Sizes.Count && i * 2 < grid.RowDefinitions.Count)
{ {
groupNode.Sizes[i] = grid.RowDefinitions[i * 2].Height; var newHeight = grid.RowDefinitions[i * 2].Height;
if (!groupNode.Sizes[i].Equals(newHeight))
{
_isSyncingSizes = true;
groupNode.Sizes[i] = newHeight;
changed = true;
} }
} }
} }
} }
if (changed)
{
_isSyncingSizes = false;
}
}
private UIElement CreatePanelUI(DockPanelNode panelNode) private UIElement CreatePanelUI(DockPanelNode panelNode)
{ {
var tabView = new Ghost.Editor.Controls.NavigationTabView var tabView = new Ghost.Editor.Controls.NavigationTabView

View File

@@ -19,6 +19,7 @@ public sealed partial class DockLayout
if (node is DockGroupNode groupNode) if (node is DockGroupNode groupNode)
{ {
((INotifyCollectionChanged)groupNode.Children).CollectionChanged += OnChildrenCollectionChanged; ((INotifyCollectionChanged)groupNode.Children).CollectionChanged += OnChildrenCollectionChanged;
groupNode.Sizes.CollectionChanged += OnSizesCollectionChanged;
foreach (var child in groupNode.Children) foreach (var child in groupNode.Children)
{ {
SubscribeToNode(child); SubscribeToNode(child);
@@ -38,6 +39,7 @@ public sealed partial class DockLayout
if (node is DockGroupNode groupNode) if (node is DockGroupNode groupNode)
{ {
((INotifyCollectionChanged)groupNode.Children).CollectionChanged -= OnChildrenCollectionChanged; ((INotifyCollectionChanged)groupNode.Children).CollectionChanged -= OnChildrenCollectionChanged;
groupNode.Sizes.CollectionChanged -= OnSizesCollectionChanged;
foreach (var child in groupNode.Children) foreach (var child in groupNode.Children)
{ {
UnsubscribeFromNode(child); UnsubscribeFromNode(child);
@@ -55,11 +57,20 @@ public sealed partial class DockLayout
if (node is DockGroupNode groupNode) if (node is DockGroupNode groupNode)
{ {
((INotifyCollectionChanged)groupNode.Children).CollectionChanged -= OnChildrenCollectionChanged; ((INotifyCollectionChanged)groupNode.Children).CollectionChanged -= OnChildrenCollectionChanged;
groupNode.Sizes.CollectionChanged -= OnSizesCollectionChanged;
} }
} }
_subscribedNodes.Clear(); _subscribedNodes.Clear();
} }
private void OnSizesCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (!_isSyncingSizes)
{
RenderTree();
}
}
private void OnNodePropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void OnNodePropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{ {
// Filter to structural property names // Filter to structural property names

View File

@@ -19,6 +19,7 @@ public sealed partial class DockLayout : Control
private const double DROP_EDGE_THRESHOLD = 0.25; private const double DROP_EDGE_THRESHOLD = 0.25;
private FrameworkElement? _dropTargetOverlay; private FrameworkElement? _dropTargetOverlay;
private bool _isSyncingSizes;
public DockLayout() public DockLayout()
{ {

View File

@@ -20,13 +20,46 @@ internal sealed partial class DockWindow : WindowEx
PART_DockLayout.Root = rootGroup; PART_DockLayout.Root = rootGroup;
PART_DockLayout.TabTornOff += OnTabTornOff; PART_DockLayout.TabTornOff += OnTabTornOff;
((System.Collections.Specialized.INotifyCollectionChanged)rootGroup.Children).CollectionChanged += (s, e) => RegisterCloseHandler();
}
private void RegisterCloseHandler()
{ {
if (rootGroup.Children.Count == 0) // 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)
{
if (PART_DockLayout.Root?.Children.Count == 0)
{ {
this.Close(); 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);
} }
private void OnTabTornOff(object? sender, TabTornOffEventArgs e) private void OnTabTornOff(object? sender, TabTornOffEventArgs e)