235 lines
11 KiB
C#
235 lines
11 KiB
C#
namespace Lattice.Core.Docking.Services;
|
||
|
||
/// <summary>
|
||
/// Реестр типов содержимого, который позволяет создавать экземпляры контента по типу.
|
||
/// Этот сервис является центральным для динамического создания панелей инструментов и документов.
|
||
/// </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">
|
||
/// Выбрасывается, если <paramref name="contentTypeId"/> или <paramref name="factory"/>
|
||
/// равны null.
|
||
/// </exception>
|
||
/// <exception cref="ArgumentException">
|
||
/// Выбрасывается, если <paramref name="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 (string.IsNullOrEmpty(contentTypeId.Trim()))
|
||
throw new ArgumentException("Идентификатор типа контента не может быть пустой строкой.", nameof(contentTypeId));
|
||
|
||
if (_contentTypes.ContainsKey(contentTypeId))
|
||
throw new ArgumentException($"Тип контента '{contentTypeId}' уже зарегистрирован.");
|
||
|
||
_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="ArgumentNullException">
|
||
/// Выбрасывается, если <paramref name="contentTypeId"/> равен null или пустой строке.
|
||
/// </exception>
|
||
/// <exception cref="KeyNotFoundException">
|
||
/// Выбрасывается, если тип контента не зарегистрирован.
|
||
/// </exception>
|
||
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();
|
||
content.SetId(id);
|
||
|
||
return content;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает метаданные для указанного типа контента.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <returns>
|
||
/// Метаданные типа контента или null, если тип не найден.
|
||
/// </returns>
|
||
public ContentMetadata? GetMetadata(string contentTypeId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(contentTypeId))
|
||
return null;
|
||
|
||
return _contentTypes.TryGetValue(contentTypeId, out var descriptor)
|
||
? descriptor.Metadata
|
||
: null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает все зарегистрированные типы контента.
|
||
/// </summary>
|
||
/// <returns>
|
||
/// Коллекция идентификаторов зарегистрированных типов контента.
|
||
/// </returns>
|
||
public IEnumerable<string> GetRegisteredTypes() => _contentTypes.Keys;
|
||
|
||
/// <summary>
|
||
/// Проверяет, зарегистрирован ли указанный тип контента.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <returns>
|
||
/// true, если тип контента зарегистрирован; в противном случае false.
|
||
/// </returns>
|
||
public bool IsRegistered(string contentTypeId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(contentTypeId))
|
||
return false;
|
||
|
||
return _contentTypes.ContainsKey(contentTypeId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Представляет дескриптор типа контента, содержащий информацию о фабричном методе и метаданных.
|
||
/// </summary>
|
||
private class ContentDescriptor
|
||
{
|
||
/// <summary>
|
||
/// Получает тип контента.
|
||
/// </summary>
|
||
public Type ContentType { get; }
|
||
|
||
/// <summary>
|
||
/// Получает фабричный метод для создания экземпляров контента.
|
||
/// </summary>
|
||
public Func<Abstractions.IDockContent> Factory { get; }
|
||
|
||
/// <summary>
|
||
/// Получает метаданные типа контента.
|
||
/// </summary>
|
||
public ContentMetadata Metadata { get; }
|
||
|
||
/// <summary>
|
||
/// Инициализирует новый экземпляр класса <see cref="ContentDescriptor"/>.
|
||
/// </summary>
|
||
/// <param name="contentType">Тип контента.</param>
|
||
/// <param name="factory">Фабричный метод.</param>
|
||
/// <param name="metadata">Метаданные.</param>
|
||
public ContentDescriptor(Type contentType, Func<Abstractions.IDockContent> factory,
|
||
ContentMetadata metadata)
|
||
{
|
||
ContentType = contentType;
|
||
Factory = factory;
|
||
Metadata = metadata;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Представляет метаданные типа контента, предоставляющие дополнительную информацию для отображения в UI.
|
||
/// </summary>
|
||
public class ContentMetadata
|
||
{
|
||
/// <summary>
|
||
/// Получает идентификатор типа контента.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Уникальный строковый идентификатор типа контента.
|
||
/// </value>
|
||
public string ContentTypeId { get; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает отображаемое имя типа контента.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Имя типа контента, отображаемое пользователю.
|
||
/// </value>
|
||
public string DisplayName { get; set; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает описание типа контента.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Текстовое описание функциональности контента.
|
||
/// </value>
|
||
public string Description { get; set; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает имя ресурса для иконки типа контента.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Имя ресурса иконки или null, если иконка не определена.
|
||
/// </value>
|
||
public string? IconResource { get; set; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает значение, указывающее, является ли контент документом
|
||
/// (а не инструментальной панелью).
|
||
/// </summary>
|
||
/// <value>
|
||
/// true, если контент является документом; в противном случае false.
|
||
/// </value>
|
||
public bool IsDocument { get; set; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает ширину контента по умолчанию.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Ширина контента в пикселях. Значение по умолчанию: 300.
|
||
/// </value>
|
||
public double DefaultWidth { get; set; } = 300;
|
||
|
||
/// <summary>
|
||
/// Получает или задает высоту контента по умолчанию.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Высота контента в пикселях. Значение по умолчанию: 200.
|
||
/// </value>
|
||
public double DefaultHeight { get; set; } = 200;
|
||
|
||
/// <summary>
|
||
/// Инициализирует новый экземпляр класса <see cref="ContentMetadata"/>.
|
||
/// </summary>
|
||
/// <param name="contentTypeId">Идентификатор типа контента.</param>
|
||
/// <param name="displayName">Отображаемое имя типа контента.</param>
|
||
/// <exception cref="ArgumentNullException">
|
||
/// Выбрасывается, если <paramref name="contentTypeId"/> или <paramref name="displayName"/>
|
||
/// равны null.
|
||
/// </exception>
|
||
public ContentMetadata(string contentTypeId, string displayName)
|
||
{
|
||
ContentTypeId = contentTypeId ?? throw new ArgumentNullException(nameof(contentTypeId));
|
||
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName));
|
||
Description = string.Empty;
|
||
}
|
||
} |