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(); } }