namespace Lattice.Core.Docking.Services; /// /// Реестр типов содержимого, который позволяет создавать экземпляры контента по типу. /// Этот сервис является центральным для динамического создания панелей инструментов и документов в IDE. /// /// /// Реализует шаблон "Фабрика" для создания экземпляров . /// Позволяет регистрировать фабричные методы для различных типов контента, что обеспечивает /// позднее связывание и возможность плагинной архитектуры. /// public class ContentRegistry { private readonly Dictionary _contentTypes = new(); /// /// Регистрирует фабричный метод для создания контента указанного типа. /// /// Тип контента, реализующий . /// Уникальный идентификатор типа контента. /// Фабричный метод для создания экземпляров контента. /// Метаданные типа контента (опционально). /// Выбрасывается, если contentTypeId или factory равны null. /// Выбрасывается, если contentTypeId уже зарегистрирован. 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($"Content type '{contentTypeId}' is already registered."); _contentTypes[contentTypeId] = new ContentDescriptor( typeof(T), () => factory(), metadata ?? new ContentMetadata(contentTypeId, typeof(T).Name) ); } /// /// Создает новый экземпляр контента указанного типа с заданным идентификатором. /// /// Идентификатор типа контента. /// Уникальный идентификатор для создаваемого экземпляра контента. /// Новый экземпляр контента. /// Выбрасывается, если тип контента не зарегистрирован. public Abstractions.IDockContent CreateContent(string contentTypeId, string id) { if (!_contentTypes.TryGetValue(contentTypeId, out var descriptor)) throw new KeyNotFoundException($"Content type '{contentTypeId}' is not registered."); 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) { return _contentTypes.TryGetValue(contentTypeId, out var descriptor) ? descriptor.Metadata : null; } /// /// Получает все зарегистрированные типы контента. /// /// Коллекция идентификаторов зарегистрированных типов контента. public IEnumerable GetRegisteredTypes() => _contentTypes.Keys; /// /// Проверяет, зарегистрирован ли указанный тип контента. /// public bool IsRegistered(string contentTypeId) => _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; } /// /// Имя ресурса для иконки (опционально). /// public string? IconResource { get; set; } /// /// Признак того, что контент является документом (а не инструментальной панелью). /// public bool IsDocument { get; set; } /// /// Минимальная ширина контента в пикселях. /// public double DefaultWidth { get; set; } = 300; /// /// Минимальная высота контента в пикселях. /// public double DefaultHeight { get; set; } = 200; /// /// Инициализирует новый экземпляр метаданных контента. /// /// Идентификатор типа контента. /// Отображаемое имя. public ContentMetadata(string contentTypeId, string displayName) { ContentTypeId = contentTypeId; DisplayName = displayName; Description = string.Empty; } }