namespace Lattice.Core.Docking.Services;
///
/// Реестр типов содержимого, который позволяет создавать экземпляры контента по типу.
/// Этот сервис является центральным для динамического создания панелей инструментов и документов.
///
///
/// Реализует шаблон "Фабрика" для создания экземпляров .
/// Позволяет регистрировать фабричные методы для различных типов контента, что обеспечивает
/// позднее связывание и возможность плагинной архитектуры.
///
public class ContentRegistry
{
private readonly Dictionary _contentTypes = new();
///
/// Регистрирует фабричный метод для создания контента указанного типа.
///
///
/// Тип контента, реализующий .
///
/// Уникальный идентификатор типа контента.
/// Фабричный метод для создания экземпляров контента.
/// Метаданные типа контента (опционально).
///
/// Выбрасывается, если или
/// равны null.
///
///
/// Выбрасывается, если уже зарегистрирован.
///
public void Register(string contentTypeId, Func factory, ContentMetadata? metadata = null)
where T : Abstractions.IDockContent
{
if (string.IsNullOrWhiteSpace(contentTypeId))
throw new ArgumentNullException(nameof(contentTypeId));
if (factory == null)
throw new ArgumentNullException(nameof(factory));
if (_contentTypes.ContainsKey(contentTypeId))
throw new ArgumentException($"Тип контента '{contentTypeId}' уже зарегистрирован.");
_contentTypes[contentTypeId] = new ContentDescriptor(
typeof(T),
() => factory(),
metadata ?? new ContentMetadata(contentTypeId, typeof(T).Name)
);
}
///
/// Создает новый экземпляр контента указанного типа с заданным идентификатором.
///
/// Идентификатор типа контента.
/// Уникальный идентификатор для создаваемого экземпляра контента.
///
/// Новый экземпляр контента.
///
///
/// Выбрасывается, если равен null или пустой строке.
///
///
/// Выбрасывается, если тип контента не зарегистрирован.
///
public Abstractions.IDockContent CreateContent(string contentTypeId, string id)
{
if (string.IsNullOrWhiteSpace(contentTypeId))
throw new ArgumentNullException(nameof(contentTypeId));
if (!_contentTypes.TryGetValue(contentTypeId, out var descriptor))
throw new KeyNotFoundException($"Тип контента '{contentTypeId}' не зарегистрирован.");
var content = descriptor.Factory();
// Устанавливаем ID через рефлексию, если есть свойство Id
var property = content.GetType().GetProperty("Id");
if (property != null && property.CanWrite)
{
property.SetValue(content, id);
}
return content;
}
///
/// Получает метаданные для указанного типа контента.
///
/// Идентификатор типа контента.
///
/// Метаданные типа контента или null, если тип не найден.
///
public ContentMetadata? GetMetadata(string contentTypeId)
{
if (string.IsNullOrWhiteSpace(contentTypeId))
return null;
return _contentTypes.TryGetValue(contentTypeId, out var descriptor)
? descriptor.Metadata
: null;
}
///
/// Получает все зарегистрированные типы контента.
///
///
/// Коллекция идентификаторов зарегистрированных типов контента.
///
public IEnumerable GetRegisteredTypes() => _contentTypes.Keys;
///
/// Проверяет, зарегистрирован ли указанный тип контента.
///
/// Идентификатор типа контента.
///
/// true, если тип контента зарегистрирован; в противном случае false.
///
public bool IsRegistered(string contentTypeId)
{
if (string.IsNullOrWhiteSpace(contentTypeId))
return false;
return _contentTypes.ContainsKey(contentTypeId);
}
///
/// Представляет дескриптор типа контента, содержащий информацию о фабричном методе и метаданных.
///
private class ContentDescriptor
{
///
/// Получает тип контента.
///
public Type ContentType { get; }
///
/// Получает фабричный метод для создания экземпляров контента.
///
public Func Factory { get; }
///
/// Получает метаданные типа контента.
///
public ContentMetadata Metadata { get; }
///
/// Инициализирует новый экземпляр класса .
///
/// Тип контента.
/// Фабричный метод.
/// Метаданные.
public ContentDescriptor(Type contentType, Func factory,
ContentMetadata metadata)
{
ContentType = contentType;
Factory = factory;
Metadata = metadata;
}
}
}
///
/// Представляет метаданные типа контента, предоставляющие дополнительную информацию для отображения в UI.
///
public class ContentMetadata
{
///
/// Получает идентификатор типа контента.
///
///
/// Уникальный строковый идентификатор типа контента.
///
public string ContentTypeId { get; }
///
/// Получает или задает отображаемое имя типа контента.
///
///
/// Имя типа контента, отображаемое пользователю.
///
public string DisplayName { get; set; }
///
/// Получает или задает описание типа контента.
///
///
/// Текстовое описание функциональности контента.
///
public string Description { get; set; }
///
/// Получает или задает имя ресурса для иконки типа контента.
///
///
/// Имя ресурса иконки или null, если иконка не определена.
///
public string? IconResource { get; set; }
///
/// Получает или задает значение, указывающее, является ли контент документом
/// (а не инструментальной панелью).
///
///
/// true, если контент является документом; в противном случае false.
///
public bool IsDocument { get; set; }
///
/// Получает или задает ширину контента по умолчанию.
///
///
/// Ширина контента в пикселях. Значение по умолчанию: 300.
///
public double DefaultWidth { get; set; } = 300;
///
/// Получает или задает высоту контента по умолчанию.
///
///
/// Высота контента в пикселях. Значение по умолчанию: 200.
///
public double DefaultHeight { get; set; } = 200;
///
/// Инициализирует новый экземпляр класса .
///
/// Идентификатор типа контента.
/// Отображаемое имя типа контента.
///
/// Выбрасывается, если или
/// равны null.
///
public ContentMetadata(string contentTypeId, string displayName)
{
ContentTypeId = contentTypeId ?? throw new ArgumentNullException(nameof(contentTypeId));
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName));
Description = string.Empty;
}
}