Доработан winui

This commit is contained in:
2026-02-01 09:26:13 +03:00
parent 584df249f6
commit e8b4cb9881
26 changed files with 1842 additions and 2373 deletions

View File

@@ -5,85 +5,44 @@ using System.Runtime.CompilerServices;
namespace Lattice.Core.Docking.Models;
/// <summary>
/// Представляет конечный узел (лист) дерева компоновки, который непосредственно
/// содержит коллекцию вкладок с контентом. Этот класс является контейнером для
/// отображаемого пользователю содержимого.
/// </summary>
/// <remarks>
/// Лист является основным элементом, с которым взаимодействует пользователь
/// при работе с документами или инструментальными панелями в IDE-подобных
/// приложениях.
/// </remarks>
public class DockLeaf : IDockContainer, INotifyPropertyChanged
{
/// <summary>
/// Происходит при изменении значения свойства.
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;
private readonly ObservableCollection<IDockContent> _items = new();
private IDockContent? _activeContent;
private string _id;
private TabPlacement _tabPlacement = TabPlacement.Bottom;
private IDockElement? _parent;
private double _width;
private double _height;
private TabPlacement _tabPlacement = TabPlacement.Top;
/// <summary>
/// Получает или задает уникальный идентификатор листа.
/// </summary>
/// <value>
/// Строковый идентификатор, уникальный в пределах дерева компоновки.
/// </value>
public string Id
public event PropertyChangedEventHandler? PropertyChanged;
public DockLeaf()
{
get => _id;
internal set
_items.CollectionChanged += (s, e) => OnPropertyChanged(nameof(Children));
}
public string Id { get; } = Guid.NewGuid().ToString();
public IDockElement? Parent
{
get => _parent;
set
{
if (_id != value)
if (_parent != value)
{
_id = value;
_parent = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// Получает или задает родительский элемент в иерархии дерева компоновки.
/// </summary>
/// <value>
/// Родительский элемент или null, если этот лист является корневым.
/// </value>
public IDockElement? Parent { get; set; }
/// <summary>
/// Получает список вкладок, содержащихся в данном контейнере.
/// </summary>
/// <value>
/// Коллекция объектов, реализующих <see cref="IDockContent"/>.
/// </value>
/// <remarks>
/// Эта коллекция является наблюдаемой (ObservableCollection), что позволяет
/// автоматически обновлять пользовательский интерфейс при добавлении или
/// удалении вкладок.
/// </remarks>
public IList<IDockContent> Children => _items;
/// <summary>
/// Получает или задает активную (выбранную) вкладку в контейнере.
/// </summary>
/// <value>
/// Активная вкладка или null, если в контейнере нет вкладок.
/// </value>
/// <remarks>
/// При установке нового значения проверяется, что вкладка действительно
/// содержится в коллекции <see cref="Children"/>.
/// Изменение этого свойства вызывает событие <see cref="PropertyChanged"/>.
/// </remarks>
public IDockContent? ActiveContent
{
get => _activeContent;
set
{
if (value != null && !_items.Contains(value)) return;
if (_activeContent != value)
{
_activeContent = value;
@@ -92,48 +51,35 @@ public class DockLeaf : IDockContainer, INotifyPropertyChanged
}
}
/// <summary>
/// Получает или задает желаемую ширину элемента.
/// </summary>
/// <value>
/// Ширина в пикселях или относительных единицах.
/// </value>
public double Width { get; set; }
public double Width
{
get => _width;
set
{
if (Math.Abs(_width - value) > 0.001)
{
_width = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// Получает или задает желаемую высоту элемента.
/// </summary>
/// <value>
/// Высота в пикселях или относительных единицах.
/// </value>
public double Height { get; set; }
public double Height
{
get => _height;
set
{
if (Math.Abs(_height - value) > 0.001)
{
_height = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// Получает или задает минимально допустимую ширину элемента.
/// </summary>
/// <value>
/// Минимальная ширина в пикселях. Значение по умолчанию: 100.
/// </value>
public double MinWidth { get; set; } = 100;
/// <summary>
/// Получает или задает минимально допустимую высоту элемента.
/// </summary>
/// <value>
/// Минимальная высота в пикселях. Значение по умолчанию: 100.
/// </value>
public double MinHeight { get; set; } = 100;
/// <summary>
/// Получает или задает положение полосы вкладок в контейнере.
/// </summary>
/// <value>
/// Значение перечисления <see cref="TabPlacement"/>, определяющее,
/// где располагаются вкладки относительно содержимого.
/// </value>
/// <remarks>
/// Поддерживаются все четыре стороны: верх, низ, лево, право.
/// </remarks>
public TabPlacement TabPlacement
{
get => _tabPlacement;
@@ -147,47 +93,10 @@ public class DockLeaf : IDockContainer, INotifyPropertyChanged
}
}
/// <summary>
/// Инициализирует новый экземпляр класса <see cref="DockLeaf"/>.
/// </summary>
/// <param name="id">
/// Уникальный идентификатор листа. Если не указан, генерируется новый GUID.
/// </param>
/// <remarks>
/// Создает пустой лист с коллекцией вкладок и генерирует уникальный
/// идентификатор, если он не был предоставлен.
/// </remarks>
public DockLeaf(string? id = null)
{
_id = id ?? Guid.NewGuid().ToString();
}
/// <summary>
/// Вызывает событие <see cref="PropertyChanged"/>.
/// </summary>
/// <param name="name">
/// Имя изменившегося свойства. Если не указано, определяется автоматически.
/// </param>
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
/// <summary>
/// Добавляет контент в контейнер и делает его активным.
/// </summary>
/// <param name="content">
/// Контент для добавления.
/// </param>
/// <remarks>
/// Если контент уже содержится в коллекции, он не добавляется повторно,
/// но становится активным.
/// Этот метод обновляет свойство <see cref="ActiveContent"/> и вызывает
/// соответствующее событие изменения свойства.
/// </remarks>
public void AddContent(IDockContent content)
{
if (content == null) return;
if (content == null)
throw new ArgumentNullException(nameof(content));
if (!_items.Contains(content))
{
@@ -196,22 +105,10 @@ public class DockLeaf : IDockContainer, INotifyPropertyChanged
ActiveContent = content;
}
/// <summary>
/// Удаляет контент из контейнера.
/// </summary>
/// <param name="content">
/// Контент для удаления.
/// </param>
/// <remarks>
/// Если удаляемый контент является активным, автоматически выбирается
/// новая активная вкладка (следующая в списке или предыдущая, если удалена
/// последняя).
/// Если после удаления контейнер становится пустым, он может быть удален
/// из дерева макета системой компоновки.
/// </remarks>
public void RemoveContent(IDockContent content)
{
if (content == null) return;
if (content == null)
throw new ArgumentNullException(nameof(content));
int index = _items.IndexOf(content);
if (index == -1) return;
@@ -226,4 +123,9 @@ public class DockLeaf : IDockContainer, INotifyPropertyChanged
ActiveContent = null;
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}