Files
Lattice/Lattice.Core.DragDrop/Models/DragInfo.cs

247 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Lattice.Core.Geometry;
using System.Collections.Concurrent;
namespace Lattice.Core.DragDrop.Models;
/// <summary>
/// Содержит информацию о начале операции перетаскивания.
/// Этот класс передается от источника перетаскивания к системе перетаскивания
/// для инициализации и управления операцией.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="DragInfo"/> является ключевым компонентом системы перетаскивания,
/// инкапсулирующим все необходимые данные для начала операции. Он содержит:
/// </para>
/// <list type="bullet">
/// <item>Данные для передачи</item>
/// <item>Разрешенные эффекты перетаскивания</item>
/// <item>Начальную позицию операции</item>
/// <item>Ссылку на источник перетаскивания</item>
/// <item>Дополнительные параметры операции</item>
/// </list>
/// <para>
/// Этот класс используется как внутренний механизм передачи данных между
/// <see cref="Abstractions.IDragSource"/> и системой управления перетаскиванием.
/// </para>
/// </remarks>
public class DragInfo : IDisposable, ICloneable
{
private readonly ConcurrentDictionary<string, object> _parameters = new();
private bool _disposed;
/// <summary>
/// Получает данные, которые передаются в операции перетаскивания.
/// </summary>
/// <value>
/// Объект, содержащий данные для передачи. Может быть любого типа,
/// поддерживаемого системой перетаскивания.
/// </value>
/// <remarks>
/// Эти данные будут доступны цели сброса через <see cref="DropInfo.Data"/>.
/// Важно, чтобы данные были сериализуемыми, если операция перетаскивания
/// может выходить за пределы процесса приложения.
/// </remarks>
public object Data { get; }
/// <summary>
/// Получает разрешенные эффекты для этой операции перетаскивания.
/// </summary>
/// <value>
/// Комбинация флагов <see cref="Enums.DragDropEffects"/>, определяющая,
/// какие операции разрешены для этого перетаскивания.
/// </value>
/// <remarks>
/// Этот параметр используется системой для фильтрации допустимых операций
/// и предоставления соответствующей визуальной обратной связи пользователю.
/// </remarks>
public Enums.DragDropEffects AllowedEffects { get; }
/// <summary>
/// Получает начальную позицию операции перетаскивания в координатах экрана.
/// </summary>
/// <value>
/// Точка в экранных координатах, где была начата операция перетаскивания.
/// </value>
/// <remarks>
/// Эта позиция используется для вычисления смещения при создании визуального
/// представления перетаскивания и для определения порога начала операции.
/// </remarks>
public Point StartPosition { get; }
/// <summary>
/// Получает источник перетаскивания, который инициировал операцию.
/// </summary>
/// <value>
/// Объект, реализующий <see cref="Abstractions.IDragSource"/>, или null,
/// если источник не доступен или не требуется.
/// </value>
/// <remarks>
/// Эта ссылка может использоваться для уведомления источника о результате
/// операции перетаскивания (завершении или отмене).
/// </remarks>
public object? Source { get; }
/// <summary>
/// Получает или задает дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
/// </summary>
/// <value>
/// Словарь, содержащий пары ключ-значение с дополнительными параметрами.
/// </value>
/// <remarks>
/// Используется для передачи контекстной информации, которая не входит
/// в стандартный набор свойств, но может быть полезной для обработки
/// операции перетаскивания.
/// </remarks>
public IReadOnlyDictionary<string, object> Parameters => _parameters;
/// <summary>
/// Инициализирует новый экземпляр класса <see cref="DragInfo"/>.
/// </summary>
/// <param name="data">
/// Данные, которые передаются в операции перетаскивания.
/// Не может быть null.
/// </param>
/// <param name="allowedEffects">
/// Разрешенные эффекты для этой операции перетаскивания.
/// </param>
/// <param name="startPosition">
/// Начальная позиция операции перетаскивания в координатах экрана.
/// </param>
/// <param name="source">
/// Источник перетаскивания, который инициировал операцию. Может быть null.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, когда <paramref name="data"/> равен null.
/// </exception>
/// <remarks>
/// Конструктор создает экземпляр <see cref="DragInfo"/> с указанными
/// параметрами и инициализирует коллекцию параметров пустым словарем.
/// </remarks>
public DragInfo(object data, Enums.DragDropEffects allowedEffects, Point startPosition, object? source = null)
{
Data = data ?? throw new ArgumentNullException(nameof(data));
// Проверка допустимых значений перечисления
if (!Enum.IsDefined(typeof(Enums.DragDropEffects), allowedEffects))
{
throw new ArgumentException(
$"Недопустимое значение для {nameof(allowedEffects)}: {allowedEffects}",
nameof(allowedEffects));
}
AllowedEffects = allowedEffects;
StartPosition = startPosition;
Source = source;
}
/// <summary>
/// Создает новый экземпляр <see cref="DragInfo"/> с теми же данными,
/// но новой позицией.
/// </summary>
/// <param name="newPosition">
/// Новая позиция для информации о перетаскивании.
/// </param>
/// <returns>
/// Новый экземпляр <see cref="DragInfo"/> с обновленной позицией.
/// </returns>
/// <remarks>
/// Этот метод используется для обновления информации о перетаскивании
/// при перемещении курсора, сохраняя исходные данные и параметры.
/// </remarks>
public DragInfo CloneWithPosition(Point newPosition)
{
ThrowIfDisposed();
var clone = new DragInfo(Data, AllowedEffects, newPosition, Source)
{
_disposed = false,
};
foreach (var kvp in _parameters)
{
clone._parameters[kvp.Key] = kvp.Value;
}
return clone;
}
/// <summary>
/// Создает новый экземпляр <see cref="DragInfo"/> с теми же данными.
/// </summary>
public DragInfo Clone() => new DragInfo(Data, AllowedEffects, StartPosition, Source);
/// <inheritdoc/>
object ICloneable.Clone() => this.Clone();
/// <summary>
/// Получает или дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
/// </summary>
public T? GetParameter<T>(string key, T? defaultValue = default)
{
if (Parameters.TryGetValue(key, out var value) && value is T typedValue)
{
return typedValue;
}
return defaultValue;
}
/// <summary>
/// Получает или дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
/// </summary>
public bool TryGetParameter<T>(string key, out T? value)
{
value = default;
if (_parameters.TryGetValue(key, out var objValue) && objValue is T typedValue)
{
value = typedValue;
return true;
}
return false;
}
/// <summary>
/// Задает дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
/// </summary>
public void SetParameter<T>(string key, T value)
{
_parameters[key] = value!;
}
/// <summary>
/// Освобождает ресурсы.
/// </summary>
public void Dispose()
{
if (_disposed) return;
foreach (var value in _parameters.Values)
{
if (value is IDisposable disposable)
{
disposable.Dispose();
}
}
_parameters.Clear();
_disposed = true;
GC.SuppressFinalize(this);
}
private void ThrowIfDisposed()
{
if (_disposed)
throw new ObjectDisposedException(nameof(DragInfo));
}
~DragInfo()
{
Dispose();
}
}