using Lattice.Core.Geometry;
using System.Collections.Concurrent;
namespace Lattice.Core.DragDrop.Models;
///
/// Содержит информацию о начале операции перетаскивания.
/// Этот класс передается от источника перетаскивания к системе перетаскивания
/// для инициализации и управления операцией.
///
///
///
/// является ключевым компонентом системы перетаскивания,
/// инкапсулирующим все необходимые данные для начала операции. Он содержит:
///
///
/// - Данные для передачи
/// - Разрешенные эффекты перетаскивания
/// - Начальную позицию операции
/// - Ссылку на источник перетаскивания
/// - Дополнительные параметры операции
///
///
/// Этот класс используется как внутренний механизм передачи данных между
/// и системой управления перетаскиванием.
///
///
public class DragInfo : IDisposable, ICloneable
{
private readonly ConcurrentDictionary _parameters = new();
private bool _disposed;
///
/// Получает данные, которые передаются в операции перетаскивания.
///
///
/// Объект, содержащий данные для передачи. Может быть любого типа,
/// поддерживаемого системой перетаскивания.
///
///
/// Эти данные будут доступны цели сброса через .
/// Важно, чтобы данные были сериализуемыми, если операция перетаскивания
/// может выходить за пределы процесса приложения.
///
public object Data { get; }
///
/// Получает разрешенные эффекты для этой операции перетаскивания.
///
///
/// Комбинация флагов , определяющая,
/// какие операции разрешены для этого перетаскивания.
///
///
/// Этот параметр используется системой для фильтрации допустимых операций
/// и предоставления соответствующей визуальной обратной связи пользователю.
///
public Enums.DragDropEffects AllowedEffects { get; }
///
/// Получает начальную позицию операции перетаскивания в координатах экрана.
///
///
/// Точка в экранных координатах, где была начата операция перетаскивания.
///
///
/// Эта позиция используется для вычисления смещения при создании визуального
/// представления перетаскивания и для определения порога начала операции.
///
public Point StartPosition { get; }
///
/// Получает источник перетаскивания, который инициировал операцию.
///
///
/// Объект, реализующий , или null,
/// если источник не доступен или не требуется.
///
///
/// Эта ссылка может использоваться для уведомления источника о результате
/// операции перетаскивания (завершении или отмене).
///
public object? Source { get; }
///
/// Получает или задает дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
///
///
/// Словарь, содержащий пары ключ-значение с дополнительными параметрами.
///
///
/// Используется для передачи контекстной информации, которая не входит
/// в стандартный набор свойств, но может быть полезной для обработки
/// операции перетаскивания.
///
public IReadOnlyDictionary Parameters => _parameters;
///
/// Инициализирует новый экземпляр класса .
///
///
/// Данные, которые передаются в операции перетаскивания.
/// Не может быть null.
///
///
/// Разрешенные эффекты для этой операции перетаскивания.
///
///
/// Начальная позиция операции перетаскивания в координатах экрана.
///
///
/// Источник перетаскивания, который инициировал операцию. Может быть null.
///
///
/// Выбрасывается, когда равен null.
///
///
/// Конструктор создает экземпляр с указанными
/// параметрами и инициализирует коллекцию параметров пустым словарем.
///
public DragInfo(object data, Enums.DragDropEffects allowedEffects, Point startPosition, object? source = null)
{
Data = data ?? throw new ArgumentNullException(nameof(data));
AllowedEffects = allowedEffects;
StartPosition = startPosition;
Source = source;
}
///
/// Создает новый экземпляр с теми же данными,
/// но новой позицией.
///
///
/// Новая позиция для информации о перетаскивании.
///
///
/// Новый экземпляр с обновленной позицией.
///
///
/// Этот метод используется для обновления информации о перетаскивании
/// при перемещении курсора, сохраняя исходные данные и параметры.
///
public DragInfo CloneWithPosition(Point newPosition)
{
ThrowIfDisposed();
var clone = new DragInfo(Data, AllowedEffects, newPosition, Source);
foreach (var kvp in _parameters)
{
clone._parameters[kvp.Key] = kvp.Value;
}
return clone;
}
///
/// Создает новый экземпляр с теми же данными.
///
public DragInfo Clone() => new DragInfo(Data, AllowedEffects, StartPosition, Source);
///
object ICloneable.Clone() => this.Clone();
///
/// Получает или дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
///
public T? GetParameter(string key, T? defaultValue = default)
{
if (Parameters.TryGetValue(key, out var value) && value is T typedValue)
{
return typedValue;
}
return defaultValue;
}
///
/// Получает или дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
///
public bool TryGetParameter(string key, out T? value)
{
value = default;
if (_parameters.TryGetValue(key, out var objValue) && objValue is T typedValue)
{
value = typedValue;
return true;
}
return false;
}
///
/// Задает дополнительные параметры, специфичные для конкретной
/// реализации перетаскивания.
///
public void SetParameter(string key, T value)
{
_parameters[key] = value!;
}
///
/// Освобождает ресурсы.
///
public void Dispose()
{
if (_disposed) return;
_parameters.Clear();
_disposed = true;
GC.SuppressFinalize(this);
}
private void ThrowIfDisposed()
{
if (_disposed)
throw new ObjectDisposedException(nameof(DragInfo));
}
~DragInfo()
{
Dispose();
}
}