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; using System.Threading; using System.Threading.Tasks; namespace Lattice.UI.DragDrop.Behaviors; /// /// Базовый класс поведения цели сброса. /// /// Тип UI элемента. public abstract class DropTargetBehaviorBase : IDropTarget where TElement : class { private IDragDropService? _dragDropService; private string? _registrationId; private TElement? _associatedElement; private Rect _currentBounds; /// /// Получает или задает связанный элемент. /// protected TElement? AssociatedElement { get => _associatedElement; set { if (_associatedElement != value) { UnregisterFromService(); _associatedElement = value; RegisterToService(); } } } /// /// Получает или задает приоритет цели сброса. /// public int Priority { get; set; } /// /// Получает или задает группу цели сброса. /// public string? Group { get; set; } /// /// Получает сервис перетаскивания. /// protected IDragDropService DragDropService { get { if (_dragDropService == null) { _dragDropService = ServiceProvider.GetRequiredService(); } return _dragDropService; } } /// /// Получает провайдер сервисов. /// protected IServiceProvider ServiceProvider { get; } /// /// Получает текущие границы элемента в экранных координатах. /// protected Rect CurrentBounds => _currentBounds; /// /// Инициализирует новый экземпляр класса . /// /// Провайдер сервисов. protected DropTargetBehaviorBase(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } /// /// Вызывается при прикреплении к элементу. /// protected virtual void AttachToElement() { if (_associatedElement != null) { SubscribeToEvents(_associatedElement); UpdateBounds(); RegisterToService(); } } /// /// Вызывается при откреплении от элемента. /// protected virtual void DetachFromElement() { if (_associatedElement != null) { UnsubscribeFromEvents(_associatedElement); UnregisterFromService(); } } /// /// Подписывается на события элемента. /// /// Элемент. protected abstract void SubscribeToEvents(TElement element); /// /// Отписывается от событий элемента. /// /// Элемент. protected abstract void UnsubscribeFromEvents(TElement element); /// /// Обновляет границы элемента в экранных координатах. /// protected virtual void UpdateBounds() { if (_associatedElement != null) { _currentBounds = GetScreenBounds(_associatedElement); // Обновляем регистрацию в сервисе if (_registrationId != null) { DragDropService.UpdateDropTargetBounds(_registrationId, _currentBounds); } } } /// /// Получает границы элемента в экранных координатах. /// /// Элемент. /// Границы в экранных координатах. protected abstract Rect GetScreenBounds(TElement element); /// /// Регистрирует цель в сервисе перетаскивания. /// protected virtual void RegisterToService() { if (_associatedElement != null && _registrationId == null) { UpdateBounds(); _registrationId = DragDropService.RegisterDropTarget(this, _currentBounds, Priority, Group); } } /// /// Отменяет регистрацию цели в сервисе перетаскивания. /// protected virtual void UnregisterFromService() { if (_registrationId != null) { DragDropService.UnregisterDropTarget(_registrationId); _registrationId = null; } } /// /// Вызывается при изменении размера или позиции элемента. /// protected virtual void OnElementLayoutChanged() { UpdateBounds(); } #region IDropTarget Implementation /// public abstract Task CanAcceptDropAsync(DropInfo dropInfo, CancellationToken ct = default); /// public virtual async Task DragOverAsync(DropInfo dropInfo, CancellationToken ct = default) { // Базовая реализация устанавливает эффект по умолчанию if (await CanAcceptDropAsync(dropInfo)) { // Установить эффект по умолчанию, если он разрешен if (dropInfo.CanAcceptEffect(Core.DragDrop.Enums.DragDropEffects.Move)) { dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.Move; } else if (dropInfo.CanAcceptEffect(Core.DragDrop.Enums.DragDropEffects.Copy)) { dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.Copy; } else if (dropInfo.CanAcceptEffect(Core.DragDrop.Enums.DragDropEffects.Link)) { dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.Link; } } else { dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.None; } } /// public abstract Task DropAsync(DropInfo dropInfo, CancellationToken ct = default); /// public virtual async Task DragLeaveAsync(CancellationToken ct = default) { // Базовая реализация не делает ничего } #endregion /// /// Освобождает ресурсы. /// public virtual void Detach() { DetachFromElement(); _associatedElement = null; } }