DragAndDrop core
This commit is contained in:
158
Lattice.Core.Docking/Services/ContentRegistry.cs
Normal file
158
Lattice.Core.Docking/Services/ContentRegistry.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user