DragAndDrop core
This commit is contained in:
214
Lattice.UI.DragDrop/Behaviors/DropTargetBehaviorBase.cs
Normal file
214
Lattice.UI.DragDrop/Behaviors/DropTargetBehaviorBase.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Базовый класс поведения цели сброса.
|
||||
/// </summary>
|
||||
/// <typeparam name="TElement">Тип UI элемента.</typeparam>
|
||||
public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
where TElement : class
|
||||
{
|
||||
private IDragDropService? _dragDropService;
|
||||
private string? _registrationId;
|
||||
private TElement? _associatedElement;
|
||||
private Rect _currentBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает связанный элемент.
|
||||
/// </summary>
|
||||
protected TElement? AssociatedElement
|
||||
{
|
||||
get => _associatedElement;
|
||||
set
|
||||
{
|
||||
if (_associatedElement != value)
|
||||
{
|
||||
UnregisterFromService();
|
||||
_associatedElement = value;
|
||||
RegisterToService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает приоритет цели сброса.
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает группу цели сброса.
|
||||
/// </summary>
|
||||
public string? Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает сервис перетаскивания.
|
||||
/// </summary>
|
||||
protected IDragDropService DragDropService
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dragDropService == null)
|
||||
{
|
||||
_dragDropService = ServiceProvider.GetRequiredService<IDragDropService>();
|
||||
}
|
||||
return _dragDropService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает провайдер сервисов.
|
||||
/// </summary>
|
||||
protected IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущие границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
protected Rect CurrentBounds => _currentBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DropTargetBehaviorBase{TElement}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Провайдер сервисов.</param>
|
||||
protected DropTargetBehaviorBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при прикреплении к элементу.
|
||||
/// </summary>
|
||||
protected virtual void AttachToElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
{
|
||||
SubscribeToEvents(_associatedElement);
|
||||
UpdateBounds();
|
||||
RegisterToService();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при откреплении от элемента.
|
||||
/// </summary>
|
||||
protected virtual void DetachFromElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
{
|
||||
UnsubscribeFromEvents(_associatedElement);
|
||||
UnregisterFromService();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Подписывается на события элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
protected abstract void SubscribeToEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Отписывается от событий элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
protected abstract void UnsubscribeFromEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
protected virtual void UpdateBounds()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
{
|
||||
_currentBounds = GetScreenBounds(_associatedElement);
|
||||
|
||||
// Обновляем регистрацию в сервисе
|
||||
if (_registrationId != null)
|
||||
{
|
||||
DragDropService.UpdateDropTargetBounds(_registrationId, _currentBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <returns>Границы в экранных координатах.</returns>
|
||||
protected abstract Rect GetScreenBounds(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует цель в сервисе перетаскивания.
|
||||
/// </summary>
|
||||
protected virtual void RegisterToService()
|
||||
{
|
||||
if (_associatedElement != null && _registrationId == null)
|
||||
{
|
||||
UpdateBounds();
|
||||
_registrationId = DragDropService.RegisterDropTarget(this, _currentBounds, Priority, Group);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отменяет регистрацию цели в сервисе перетаскивания.
|
||||
/// </summary>
|
||||
protected virtual void UnregisterFromService()
|
||||
{
|
||||
if (_registrationId != null)
|
||||
{
|
||||
DragDropService.UnregisterDropTarget(_registrationId);
|
||||
_registrationId = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при изменении размера или позиции элемента.
|
||||
/// </summary>
|
||||
protected virtual void OnElementLayoutChanged()
|
||||
{
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
#region IDropTarget Implementation
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract bool CanAcceptDrop(DropInfo dropInfo);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void DragOver(DropInfo dropInfo)
|
||||
{
|
||||
// Базовая реализация устанавливает эффект по умолчанию
|
||||
if (CanAcceptDrop(dropInfo))
|
||||
{
|
||||
dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.Move;
|
||||
}
|
||||
else
|
||||
{
|
||||
dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract void Drop(DropInfo dropInfo);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void DragLeave()
|
||||
{
|
||||
// Базовая реализация не делает ничего
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Освобождает ресурсы.
|
||||
/// </summary>
|
||||
public virtual void Detach()
|
||||
{
|
||||
DetachFromElement();
|
||||
_associatedElement = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user