fix(dock): address reviewer feedback on tree renderer

This commit is contained in:
2026-03-28 12:57:20 +09:00
parent 979f1d64a7
commit efc9e8862d
2 changed files with 99 additions and 5 deletions

View File

@@ -1,11 +1,22 @@
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using Ghost.Editor.Core.Controls.Internal.Docking;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
namespace Ghost.Editor.View.Controls;
/// <summary>
/// A control that renders a docking layout tree.
/// </summary>
[TemplatePart(Name = PART_ROOT_GRID, Type = typeof(Grid))]
public sealed partial class DockLayout : Control
{
private const string PART_ROOT_GRID = "PART_RootGrid";
public DockLayout()
{
DefaultStyleKey = typeof(DockLayout);
@@ -24,13 +35,79 @@ public sealed partial class DockLayout : Control
{
if (d is DockLayout layout)
{
if (e.OldValue is DockGroupNode oldRoot)
{
layout.UnsubscribeFromNode(oldRoot);
}
if (e.NewValue is DockGroupNode newRoot)
{
layout.SubscribeToNode(newRoot);
}
layout.RenderTree();
}
}
private void SubscribeToNode(DockNode node)
{
node.PropertyChanged += OnNodePropertyChanged;
if (node is DockGroupNode groupNode)
{
((INotifyCollectionChanged)groupNode.Children).CollectionChanged += OnChildrenCollectionChanged;
foreach (var child in groupNode.Children)
{
SubscribeToNode(child);
}
}
}
private void UnsubscribeFromNode(DockNode node)
{
node.PropertyChanged -= OnNodePropertyChanged;
if (node is DockGroupNode groupNode)
{
((INotifyCollectionChanged)groupNode.Children).CollectionChanged -= OnChildrenCollectionChanged;
foreach (var child in groupNode.Children)
{
UnsubscribeFromNode(child);
}
}
}
private void OnNodePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
// Re-render on relevant property changes (e.g. Orientation)
RenderTree();
}
private void OnChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// Handle subscriptions for new/removed children
if (e.OldItems != null)
{
foreach (DockNode oldNode in e.OldItems)
{
UnsubscribeFromNode(oldNode);
}
}
if (e.NewItems != null)
{
foreach (DockNode newNode in e.NewItems)
{
SubscribeToNode(newNode);
}
}
RenderTree();
}
private void RenderTree()
{
if (GetTemplateChild("PART_RootGrid") is Grid rootGrid)
if (GetTemplateChild(PART_ROOT_GRID) is Grid rootGrid)
{
rootGrid.Children.Clear();
if (Root != null)
@@ -55,16 +132,32 @@ public sealed partial class DockLayout : Control
}
else if (node is DockPanelNode panelNode)
{
// NOTE: NavigationTabView is expected to be implemented in a future task or exists in a namespace not yet fully visible.
// For now, we use a placeholder if it's not found, but the task specifies using it.
// If it fails to compile, I will check for the correct namespace.
return new Ghost.Editor.Controls.NavigationTabView
var tabView = new Ghost.Editor.Controls.NavigationTabView
{
TabItemsSource = panelNode.Items,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
// Bind selection state
tabView.SetBinding(Selector.SelectedIndexProperty, new Binding
{
Source = panelNode,
Path = new PropertyPath(nameof(DockPanelNode.SelectedIndex)),
Mode = BindingMode.TwoWay
});
tabView.SetBinding(Selector.SelectedItemProperty, new Binding
{
Source = panelNode,
Path = new PropertyPath(nameof(DockPanelNode.SelectedItem)),
Mode = BindingMode.TwoWay
});
return tabView;
}
Debug.Fail($"Unsupported node type: {node.GetType().Name}");
return new Grid(); // Fallback
}