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
grid.SizeChanged += (s, e) => SyncSizesToModel(groupNode, grid);
grid.LayoutUpdated += (s, e) => SyncSizesToModel(groupNode, grid);
return grid;
}
private void SyncSizesToModel(DockGroupNode groupNode, Grid grid)
{
if (_isSyncingSizes) return;
bool isHorizontal = groupNode.Orientation == Orientation.Horizontal;
bool changed = false;
if (isHorizontal)
{
for (int i = 0; i < groupNode.Children.Count; i++)
{
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,10 +135,21 @@ public sealed partial class DockLayout
{
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)

View File

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

View File

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