158 lines
7.5 KiB
C#
158 lines
7.5 KiB
C#
namespace Lattice.Core.Docking.Services;
|
||
|
||
/// <summary>
|
||
/// Реестр типов содержимого, который позволяет создавать экземпляры контента по типу.
|
||
/// Этот сервис является центральным для динамического создания панелей инструментов и документов в IDE.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Реализует шаблон "Фабрика" для создания экземпляров <see cref="Abstractions.IDockContent"/>.
|
||
/// Позволяет регистрировать фабричные методы для различных типов контента, что обеспечивает
|
||
/// позднее связывание и возможность плагинной архитектуры.
|
||
/// </remarks>
|
||
public class ContentRegistry
|
||
{
|
||
private readonly Dictionary<string, ContentDescriptor> _contentTypes = new();
|
||
|
||
/// <summary>
|
||
/// Регистрирует фабричный метод для создания контента указанного типа.
|
||
/// </summary>
|
||
/// <typeparam name="T">Тип контента, реализующий <see cref="Abstractions.IDockContent"/>.</typeparam>
|
||
/// <param name="contentTypeId">Уникальный идентификатор типа контента.</param>
|
||
/// <param name="factory">Фабричный метод для создания экземпляров контента.</param>
|
||
/// <param name="metadata">Метаданные типа контента (опционально).</param>
|
||
/// <exception cref="ArgumentNullException">Выбрасывается, если contentTypeId или factory равны null.</exception>
|
||
/// <exception cref="ArgumentException">Выбрасывается, если contentTypeId уже зарегистрирован.</exception>
|
||
public void Register<T>(string contentTypeId, Func<T> 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)
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает новый экземпляр контента указанного типа с заданным идентификатором.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <param name="id">Уникальный идентификатор для создаваемого экземпляра контента.</param>
|
||
/// <returns>Новый экземпляр контента.</returns>
|
||
/// <exception cref="KeyNotFoundException">Выбрасывается, если тип контента не зарегистрирован.</exception>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает метаданные для указанного типа контента.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <returns>Метаданные типа контента или null, если тип не найден.</returns>
|
||
public ContentMetadata? GetMetadata(string contentTypeId)
|
||
{
|
||
return _contentTypes.TryGetValue(contentTypeId, out var descriptor)
|
||
? descriptor.Metadata
|
||
: null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает все зарегистрированные типы контента.
|
||
/// </summary>
|
||
/// <returns>Коллекция идентификаторов зарегистрированных типов контента.</returns>
|
||
public IEnumerable<string> GetRegisteredTypes() => _contentTypes.Keys;
|
||
|
||
/// <summary>
|
||
/// Проверяет, зарегистрирован ли указанный тип контента.
|
||
/// </summary>
|
||
public bool IsRegistered(string contentTypeId) => _contentTypes.ContainsKey(contentTypeId);
|
||
|
||
/// <summary>
|
||
/// Дескриптор типа контента, содержащий информацию о фабричном методе и метаданных.
|
||
/// </summary>
|
||
private class ContentDescriptor
|
||
{
|
||
public Type ContentType { get; }
|
||
public Func<Abstractions.IDockContent> Factory { get; }
|
||
public ContentMetadata Metadata { get; }
|
||
|
||
public ContentDescriptor(Type contentType, Func<Abstractions.IDockContent> factory, ContentMetadata metadata)
|
||
{
|
||
ContentType = contentType;
|
||
Factory = factory;
|
||
Metadata = metadata;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метаданные типа контента, предоставляющие дополнительную информацию для отображения в UI.
|
||
/// </summary>
|
||
public class ContentMetadata
|
||
{
|
||
/// <summary>
|
||
/// Идентификатор типа контента.
|
||
/// </summary>
|
||
public string ContentTypeId { get; }
|
||
|
||
/// <summary>
|
||
/// Отображаемое имя типа контента.
|
||
/// </summary>
|
||
public string DisplayName { get; set; }
|
||
|
||
/// <summary>
|
||
/// Описание типа контента.
|
||
/// </summary>
|
||
public string Description { get; set; }
|
||
|
||
/// <summary>
|
||
/// Имя ресурса для иконки (опционально).
|
||
/// </summary>
|
||
public string? IconResource { get; set; }
|
||
|
||
/// <summary>
|
||
/// Признак того, что контент является документом (а не инструментальной панелью).
|
||
/// </summary>
|
||
public bool IsDocument { get; set; }
|
||
|
||
/// <summary>
|
||
/// Минимальная ширина контента в пикселях.
|
||
/// </summary>
|
||
public double DefaultWidth { get; set; } = 300;
|
||
|
||
/// <summary>
|
||
/// Минимальная высота контента в пикселях.
|
||
/// </summary>
|
||
public double DefaultHeight { get; set; } = 200;
|
||
|
||
/// <summary>
|
||
/// Инициализирует новый экземпляр метаданных контента.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <param name="displayName">Отображаемое имя.</param>
|
||
public ContentMetadata(string contentTypeId, string displayName)
|
||
{
|
||
ContentTypeId = contentTypeId;
|
||
DisplayName = displayName;
|
||
Description = string.Empty;
|
||
}
|
||
} |