using Lattice.Core.DragDrop.Abstractions; using Lattice.Core.DragDrop.Models; using Lattice.Core.DragDrop.Services; using Lattice.Core.Geometry; using Microsoft.Extensions.DependencyInjection; using System; namespace Lattice.UI.DragDrop.Behaviors; /// /// Базовый класс поведения источника перетаскивания. /// /// Тип UI элемента. public abstract class DragSourceBehaviorBase : IDragSource where TElement : class { private IDragDropService? _dragDropService; private Point _dragStartPosition; private bool _isDragging; private TElement? _associatedElement; /// /// Получает или задает связанный элемент. /// protected TElement? AssociatedElement { get => _associatedElement; set { if (_associatedElement != value) { DetachFromElement(); _associatedElement = value; AttachToElement(); } } } /// /// Получает сервис перетаскивания. /// protected IDragDropService DragDropService { get { if (_dragDropService == null) { _dragDropService = ServiceProvider.GetRequiredService(); } return _dragDropService; } } /// /// Получает провайдер сервисов. /// protected IServiceProvider ServiceProvider { get; } /// /// Инициализирует новый экземпляр класса . /// /// Провайдер сервисов. protected DragSourceBehaviorBase(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } /// /// Вызывается при прикреплении к элементу. /// protected virtual void AttachToElement() { if (_associatedElement != null) { SubscribeToEvents(_associatedElement); } } /// /// Вызывается при откреплении от элемента. /// protected virtual void DetachFromElement() { if (_associatedElement != null) { UnsubscribeFromEvents(_associatedElement); } } /// /// Подписывается на события элемента. /// /// Элемент. protected abstract void SubscribeToEvents(TElement element); /// /// Отписывается от событий элемента. /// /// Элемент. protected abstract void UnsubscribeFromEvents(TElement element); /// /// Обрабатывает начало взаимодействия (например, нажатие мыши). /// /// Позиция в координатах элемента. protected virtual void OnInteractionStarted(Point position) { if (_isDragging) return; _dragStartPosition = position; } /// /// Обрабатывает перемещение во время взаимодействия. /// /// Позиция в координатах элемента. protected virtual void OnInteractionMoved(Point position) { if (_isDragging) return; var distance = CalculateDistance(_dragStartPosition, position); if (distance > DragDropService.DragStartThreshold) { StartDragOperation(); } } /// /// Обрабатывает завершение взаимодействия. /// protected virtual void OnInteractionEnded() { // Сброс состояния, если перетаскивание не началось if (!_isDragging) { Reset(); } } /// /// Обрабатывает отмену взаимодействия. /// protected virtual void OnInteractionCancelled() { if (_isDragging) { DragDropService.CancelDrag(); } Reset(); } /// /// Начинает операцию перетаскивания. /// protected virtual void StartDragOperation() { if (_isDragging || AssociatedElement == null) return; // Получаем начальную позицию в экранных координатах var screenPosition = ConvertToScreenCoordinates(_dragStartPosition); // Начинаем перетаскивание _isDragging = DragDropService.StartDrag(this, screenPosition); } /// /// Преобразует координаты элемента в экранные координаты. /// /// Точка в координатах элемента. /// Точка в экранных координатах. protected abstract Point ConvertToScreenCoordinates(Point point); /// /// Вычисляет расстояние между двумя точками. /// protected virtual double CalculateDistance(Point p1, Point p2) { var dx = p2.X - p1.X; var dy = p2.Y - p1.Y; return Math.Sqrt(dx * dx + dy * dy); } /// /// Сбрасывает состояние поведения. /// protected virtual void Reset() { _isDragging = false; _dragStartPosition = default; } #region IDragSource Implementation /// public abstract bool CanStartDrag(out DragInfo? dragInfo); /// public virtual bool StartDrag(DragInfo dragInfo) { // Базовая реализация всегда разрешает начало перетаскивания return true; } /// public virtual void DragCompleted(DragInfo dragInfo, Core.DragDrop.Enums.DragDropEffects effects) { _isDragging = false; // Оповещаем о завершении перетаскивания OnDragCompleted(dragInfo, effects); } /// public virtual void DragCancelled(DragInfo dragInfo) { _isDragging = false; // Оповещаем об отмене перетаскивания OnDragCancelled(dragInfo); } #endregion #region Virtual Methods for Derived Classes /// /// Вызывается при успешном завершении перетаскивания. /// /// Информация о перетаскивании. /// Примененные эффекты. protected virtual void OnDragCompleted(DragInfo dragInfo, Core.DragDrop.Enums.DragDropEffects effects) { } /// /// Вызывается при отмене перетаскивания. /// /// Информация о перетаскивании. protected virtual void OnDragCancelled(DragInfo dragInfo) { } #endregion /// /// Освобождает ресурсы. /// public virtual void Detach() { DetachFromElement(); _associatedElement = null; } }