107 lines
3.9 KiB
C#
107 lines
3.9 KiB
C#
using Lattice.Core.Abstractions;
|
|
using Lattice.Core.Models;
|
|
using Lattice.UI.Primitives;
|
|
using Microsoft.UI.Xaml;
|
|
using Microsoft.UI.Xaml.Controls;
|
|
|
|
namespace Lattice.UI.Controls;
|
|
|
|
/// <summary>
|
|
/// Корневой контрол Lattice, отвечающий за отображение и управление макетом докинга.
|
|
/// </summary>
|
|
public class LatticeDockHost : Control
|
|
{
|
|
public DockAnchorOverlay? AnchorOverlay => GetTemplateChild("AnchorOverlay") as DockAnchorOverlay;
|
|
|
|
/// <summary>
|
|
/// Определяет свойство зависимости для LayoutManager.
|
|
/// </summary>
|
|
public static readonly DependencyProperty ManagerProperty =
|
|
DependencyProperty.Register(nameof(Manager), typeof(ILayoutService), typeof(LatticeDockHost), new PropertyMetadata(null, OnManagerChanged));
|
|
|
|
/// <summary>
|
|
/// Сервис управления макетом, привязанный к данному хосту.
|
|
/// </summary>
|
|
public ILayoutService? Manager
|
|
{
|
|
get => (ILayoutService?)GetValue(ManagerProperty);
|
|
set => SetValue(ManagerProperty, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Указывает конкретный узел, который должен стать корнем для этого хоста.
|
|
/// Если null — используется Manager.Root.
|
|
/// </summary>
|
|
public static readonly DependencyProperty RootNodeProperty =
|
|
DependencyProperty.Register(nameof(RootNode), typeof(LayoutNode), typeof(LatticeDockHost), new PropertyMetadata(null, OnManagerChanged));
|
|
|
|
public LayoutNode? RootNode
|
|
{
|
|
get => (LayoutNode?)GetValue(RootNodeProperty);
|
|
set => SetValue(RootNodeProperty, value);
|
|
}
|
|
|
|
public LatticeDockHost()
|
|
{
|
|
this.DefaultStyleKey = typeof(LatticeDockHost);
|
|
}
|
|
|
|
private static void OnManagerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is LatticeDockHost host)
|
|
{
|
|
// Отписываемся от событий старого менеджера (если он был)
|
|
if (e.OldValue is ILayoutService oldService)
|
|
{
|
|
oldService.LayoutUpdated -= host.OnLayoutUpdated;
|
|
}
|
|
|
|
// Подписываемся на новый менеджер
|
|
if (e.NewValue is ILayoutService newService)
|
|
{
|
|
newService.LayoutUpdated += host.OnLayoutUpdated;
|
|
host.RebuildUI();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Именованный метод для обработки обновления макета.
|
|
/// Позволяет корректно отписываться от событий и избегать утечек памяти.
|
|
/// </summary>
|
|
private void OnLayoutUpdated(object? sender, EventArgs e)
|
|
{
|
|
// WinUI 3 требует обновления UI только из основного потока
|
|
this.DispatcherQueue.TryEnqueue(() =>
|
|
{
|
|
this.RebuildUI();
|
|
});
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Полностью перестраивает визуальное дерево на основе текущего состояния Core-движка.
|
|
/// </summary>
|
|
private void RebuildUI()
|
|
{
|
|
if (this.GetTemplateChild("LayoutPresenter") is ContentPresenter presenter)
|
|
{
|
|
// Приоритет: сначала проверяем локальный RootNode, затем глобальный Manager.Root
|
|
var effectiveRoot = RootNode ?? Manager?.Root;
|
|
|
|
if (effectiveRoot != null)
|
|
{
|
|
var rootPanel = new LayoutPanel(this);
|
|
rootPanel.Build(effectiveRoot);
|
|
presenter.Content = rootPanel;
|
|
}
|
|
else
|
|
{
|
|
presenter.Content = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|