Files
Lattice/Lattice.UI.Docking.WinUI/Controls/LatticeDockGroup.cs
2026-02-01 09:26:13 +03:00

304 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Lattice.Core.Docking.Abstractions;
using Lattice.Core.Docking.Engine;
using Lattice.Core.Docking.Models;
using Lattice.UI.Docking.Abstractions;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Lattice.UI;
public sealed class LatticeDockGroup : Control, IDockGroupControl, IDisposable
{
private readonly PropertyChangedEventHandler _modelPropertyChangedHandler;
private bool _disposed;
private DockGroup? _model;
private Grid? _rootGrid;
private ContentControl? _firstChildControl;
private ContentControl? _secondChildControl;
private LayoutManager? _layoutManager;
private IDockContextManager? _contextManager;
private bool _isSelected;
private bool _isActive;
private double _splitRatio = 0.5;
private double _splitterSize = 4.0;
public LatticeDockGroup()
{
this.DefaultStyleKey = typeof(LatticeDockGroup);
_modelPropertyChangedHandler = OnModelPropertyChanged;
this.DataContextChanged += OnDataContextChanged;
}
public IDockElement? Model
{
get => _model;
set
{
if (_model == value) return;
DetachModel();
_model = value as DockGroup;
AttachModel();
OnPropertyChanged(nameof(Model));
}
}
public LayoutManager? LayoutManager
{
get => _layoutManager;
set
{
if (_layoutManager == value) return;
_layoutManager = value;
OnPropertyChanged(nameof(LayoutManager));
}
}
public IDockContextManager? ContextManager
{
get => _contextManager;
set
{
if (_contextManager == value) return;
_contextManager = value;
OnPropertyChanged(nameof(ContextManager));
}
}
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected == value) return;
_isSelected = value;
OnPropertyChanged(nameof(IsSelected));
}
}
public bool IsActive
{
get => _isActive;
set
{
if (_isActive == value) return;
_isActive = value;
OnPropertyChanged(nameof(IsActive));
}
}
public bool CanDrag => true;
public bool CanDrop => true;
public SplitDirection Orientation
{
get => _model?.Orientation ?? SplitDirection.Horizontal;
set
{
if (_model != null && _model.Orientation != value)
{
_model.Orientation = value;
UpdateLayoutDefinitions();
}
}
}
public double SplitRatio
{
get => _splitRatio;
set
{
if (Math.Abs(_splitRatio - value) > 0.001)
{
_splitRatio = value;
UpdateLayoutDefinitions();
OnPropertyChanged(nameof(SplitRatio));
SplitRatioChanged?.Invoke(this,
new SplitRatioChangedEventArgs(value, SplitRatioChangeSource.Programmatic));
}
}
}
public double SplitterSize
{
get => _splitterSize;
set
{
if (Math.Abs(_splitterSize - value) > 0.001)
{
_splitterSize = value;
OnPropertyChanged(nameof(SplitterSize));
}
}
}
public IDockControl? FirstChild => _firstChildControl?.Content as IDockControl;
public IDockControl? SecondChild => _secondChildControl?.Content as IDockControl;
public event EventHandler<SplitRatioChangedEventArgs>? SplitRatioChanged;
public event PropertyChangedEventHandler? PropertyChanged;
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_rootGrid = GetTemplateChild("PART_Grid") as Grid;
_firstChildControl = GetTemplateChild("PART_First") as ContentControl;
_secondChildControl = GetTemplateChild("PART_Second") as ContentControl;
UpdateLayoutDefinitions();
}
private void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
Model = args.NewValue as DockGroup;
}
private void AttachModel()
{
if (_model != null)
{
_model.PropertyChanged += _modelPropertyChangedHandler;
this.DataContext = _model;
_splitRatio = _model.SplitRatio;
UpdateLayoutDefinitions();
}
}
private void DetachModel()
{
if (_model != null)
{
_model.PropertyChanged -= _modelPropertyChangedHandler;
this.DataContext = null;
}
}
private void OnModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(DockGroup.Orientation):
OnPropertyChanged(nameof(Orientation));
UpdateLayoutDefinitions();
break;
case nameof(DockGroup.SplitRatio):
if (_model != null)
{
_splitRatio = _model.SplitRatio;
OnPropertyChanged(nameof(SplitRatio));
UpdateLayoutDefinitions();
}
break;
}
}
private void UpdateLayoutDefinitions()
{
if (_rootGrid == null || _model == null) return;
_rootGrid.ColumnDefinitions.Clear();
_rootGrid.RowDefinitions.Clear();
if (_model.Orientation == SplitDirection.Horizontal)
{
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = new GridLength(_model.SplitRatio, GridUnitType.Star) });
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = GridLength.Auto });
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = new GridLength(1 - _model.SplitRatio, GridUnitType.Star) });
if (_firstChildControl != null)
{
Grid.SetColumn(_firstChildControl, 0);
Grid.SetRow(_firstChildControl, 0);
}
if (_secondChildControl != null)
{
Grid.SetColumn(_secondChildControl, 2);
Grid.SetRow(_secondChildControl, 0);
}
}
else
{
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = new GridLength(_model.SplitRatio, GridUnitType.Star) });
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = GridLength.Auto });
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = new GridLength(1 - _model.SplitRatio, GridUnitType.Star) });
if (_firstChildControl != null)
{
Grid.SetRow(_firstChildControl, 0);
Grid.SetColumn(_firstChildControl, 0);
}
if (_secondChildControl != null)
{
Grid.SetRow(_secondChildControl, 2);
Grid.SetColumn(_secondChildControl, 0);
}
}
}
public void SetChildren(IDockControl? firstChild, IDockControl? secondChild)
{
if (_firstChildControl != null)
_firstChildControl.Content = firstChild;
if (_secondChildControl != null)
_secondChildControl.Content = secondChild;
UpdateLayoutDefinitions();
}
public object? PrepareDragData()
{
return Model;
}
public bool HandleDrop(object data, DockPosition position)
{
// TODO: Реализовать обработку сброса
return false;
}
public void Refresh()
{
UpdateLayoutDefinitions();
}
public void ApplyTheme(IDockTheme theme)
{
// TODO: Реализовать применение темы
}
public void OnModelPropertyChanged(string propertyName)
{
if (_model != null)
{
OnModelPropertyChanged(_model, new PropertyChangedEventArgs(propertyName));
}
}
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void Dispose()
{
if (!_disposed)
{
DetachModel();
_disposed = true;
GC.SuppressFinalize(this);
}
}
}