Доработан проект UI под новый Core
This commit is contained in:
@@ -10,9 +10,20 @@ using System.Threading.Tasks;
|
||||
namespace Lattice.UI.DragDrop.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// Базовый класс поведения источника перетаскивания.
|
||||
/// Базовый класс поведения источника перетаскивания для UI элементов.
|
||||
/// </summary>
|
||||
/// <typeparam name="TElement">Тип UI элемента.</typeparam>
|
||||
/// <typeparam name="TElement">Тип UI элемента, к которому прикрепляется поведение.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот класс предоставляет базовую реализацию поведения перетаскивания для UI элементов.
|
||||
/// Он обрабатывает события мыши/тач, управляет порогом начала перетаскивания и
|
||||
/// интегрируется с сервисом <see cref="IDragDropService"/> из ядра.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Производные классы должны реализовать абстрактные методы для конкретной
|
||||
/// UI-платформы и предоставить логику создания информации о перетаскивании.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
where TElement : class
|
||||
{
|
||||
@@ -20,10 +31,15 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
private Point _dragStartPosition;
|
||||
private bool _isDragging;
|
||||
private TElement? _associatedElement;
|
||||
private CancellationTokenSource? _dragCancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает связанный элемент.
|
||||
/// Получает или задает связанный UI элемент.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Элемент UI, к которому прикреплено поведение перетаскивания.
|
||||
/// При изменении значения автоматически выполняется переподключение событий.
|
||||
/// </value>
|
||||
protected TElement? AssociatedElement
|
||||
{
|
||||
get => _associatedElement;
|
||||
@@ -39,8 +55,12 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает сервис перетаскивания.
|
||||
/// Получает сервис перетаскивания из контейнера зависимостей.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDragDropService"/>, используемый для управления операциями перетаскивания.
|
||||
/// При первом обращении выполняется получение сервиса из <see cref="ServiceProvider"/>.
|
||||
/// </value>
|
||||
protected IDragDropService DragDropService
|
||||
{
|
||||
get
|
||||
@@ -54,22 +74,34 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает провайдер сервисов.
|
||||
/// Получает провайдер сервисов для разрешения зависимостей.
|
||||
/// </summary>
|
||||
protected IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее, выполняется ли в данный момент операция перетаскивания.
|
||||
/// </summary>
|
||||
protected bool IsDragging => _isDragging;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DragSourceBehaviorBase{TElement}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Провайдер сервисов.</param>
|
||||
/// <param name="serviceProvider">Провайдер сервисов для разрешения зависимостей.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="serviceProvider"/> равен null.
|
||||
/// </exception>
|
||||
protected DragSourceBehaviorBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при прикреплении к элементу.
|
||||
/// Вызывается при прикреплении поведения к элементу.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализация по умолчанию подписывается на события элемента через <see cref="SubscribeToEvents"/>.
|
||||
/// Производные классы могут переопределить этот метод для дополнительной инициализации.
|
||||
/// </remarks>
|
||||
protected virtual void AttachToElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
@@ -79,8 +111,12 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при откреплении от элемента.
|
||||
/// Вызывается при откреплении поведения от элемента.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализация по умолчанию отписывается от событий элемента через <see cref="UnsubscribeFromEvents"/>.
|
||||
/// Производные классы могут переопределить этот метод для дополнительной очистки.
|
||||
/// </remarks>
|
||||
protected virtual void DetachFromElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
@@ -90,36 +126,68 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Подписывается на события элемента.
|
||||
/// Подписывается на события элемента, необходимые для отслеживания начала перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <param name="element">Элемент, к событиям которого нужно подписаться.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для подписки на события конкретной
|
||||
/// UI-платформы (например, MouseDown для WPF, PointerPressed для Avalonia).
|
||||
/// </remarks>
|
||||
protected abstract void SubscribeToEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Отписывается от событий элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <param name="element">Элемент, от событий которого нужно отписаться.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для корректной отписки
|
||||
/// от событий, на которые была выполнена подписка в <see cref="SubscribeToEvents"/>.
|
||||
/// </remarks>
|
||||
protected abstract void UnsubscribeFromEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает начало взаимодействия (например, нажатие мыши).
|
||||
/// Обрабатывает начало взаимодействия с элементом (например, нажатие кнопки мыши).
|
||||
/// </summary>
|
||||
/// <param name="position">Позиция в координатах элемента.</param>
|
||||
protected virtual async Task OnInteractionStarted(Point position)
|
||||
/// <param name="position">Позиция взаимодействия в координатах элемента.</param>
|
||||
/// <returns>Задача, представляющая асинхронную операцию.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод вызывается из обработчиков событий UI-платформы при начале
|
||||
/// взаимодействия, которое может привести к перетаскиванию.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Реализация по умолчанию сохраняет начальную позицию для последующей
|
||||
/// проверки порога перетаскивания.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual Task OnInteractionStarted(Point position)
|
||||
{
|
||||
if (_isDragging)
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
|
||||
_dragStartPosition = position;
|
||||
_dragCancellationTokenSource = new CancellationTokenSource();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает перемещение во время взаимодействия.
|
||||
/// Обрабатывает перемещение во время взаимодействия с элементом.
|
||||
/// </summary>
|
||||
/// <param name="position">Позиция в координатах элемента.</param>
|
||||
/// <param name="position">Текущая позиция взаимодействия в координатах элемента.</param>
|
||||
/// <returns>Задача, представляющая асинхронную операцию.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод вызывается при перемещении курсора/тач-точки во время удержания
|
||||
/// взаимодействия (например, перемещение мыши с нажатой кнопкой).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Реализация по умолчанию проверяет, превышено ли расстояние от начальной
|
||||
/// точки порога перетаскивания, и если да - начинает операцию перетаскивания.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual async Task OnInteractionMoved(Point position)
|
||||
{
|
||||
if (_isDragging)
|
||||
if (_isDragging || AssociatedElement == null)
|
||||
return;
|
||||
|
||||
var distance = CalculateDistance(_dragStartPosition, position);
|
||||
@@ -130,20 +198,41 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает завершение взаимодействия.
|
||||
/// Обрабатывает завершение взаимодействия с элементом.
|
||||
/// </summary>
|
||||
protected virtual async Task OnInteractionEnded()
|
||||
/// <returns>Задача, представляющая асинхронную операцию.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод вызывается при завершении взаимодействия (например, отпускании кнопки мыши).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Реализация по умолчанию сбрасывает состояние поведения, если перетаскивание не было начато.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual Task OnInteractionEnded()
|
||||
{
|
||||
// Сброс состояния, если перетаскивание не началось
|
||||
if (!_isDragging)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает отмену взаимодействия.
|
||||
/// Обрабатывает отмену взаимодействия с элементом.
|
||||
/// </summary>
|
||||
/// <returns>Задача, представляющая асинхронную операцию.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод вызывается при отмене взаимодействия (например, нажатии клавиши Escape
|
||||
/// или выходе за пределы допустимой области).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Реализация по умолчанию отменяет текущую операцию перетаскивания, если она активна,
|
||||
/// и сбрасывает состояние поведения.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual async Task OnInteractionCancelled()
|
||||
{
|
||||
if (_isDragging)
|
||||
@@ -156,16 +245,35 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
/// <summary>
|
||||
/// Начинает операцию перетаскивания.
|
||||
/// </summary>
|
||||
/// <returns>Задача, представляющая асинхронную операцию.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод преобразует начальную позицию в экранные координаты и вызывает
|
||||
/// сервис перетаскивания для начала операции.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Операция начинается только если поведение прикреплено к элементу и
|
||||
/// не выполняется другая операция перетаскивания.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual async Task StartDragOperation()
|
||||
{
|
||||
if (_isDragging || AssociatedElement == null)
|
||||
if (_isDragging || AssociatedElement == null || _dragCancellationTokenSource == null)
|
||||
return;
|
||||
|
||||
// Получаем начальную позицию в экранных координатах
|
||||
var screenPosition = ConvertToScreenCoordinates(_dragStartPosition);
|
||||
|
||||
// Начинаем перетаскивание
|
||||
_isDragging = await DragDropService.StartDragAsync(this, screenPosition);
|
||||
try
|
||||
{
|
||||
_isDragging = await DragDropService.StartDragAsync(this, screenPosition);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Операция была отменена
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,11 +281,18 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
/// </summary>
|
||||
/// <param name="point">Точка в координатах элемента.</param>
|
||||
/// <returns>Точка в экранных координатах.</returns>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для преобразования
|
||||
/// координат в соответствии с конкретной UI-платформой.
|
||||
/// </remarks>
|
||||
protected abstract Point ConvertToScreenCoordinates(Point point);
|
||||
|
||||
/// <summary>
|
||||
/// Вычисляет расстояние между двумя точками.
|
||||
/// </summary>
|
||||
/// <param name="p1">Первая точка.</param>
|
||||
/// <param name="p2">Вторая точка.</param>
|
||||
/// <returns>Расстояние между точками.</returns>
|
||||
protected virtual double CalculateDistance(Point p1, Point p2)
|
||||
{
|
||||
var dx = p2.X - p1.X;
|
||||
@@ -188,32 +303,33 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
/// <summary>
|
||||
/// Сбрасывает состояние поведения.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот метод очищает все временные данные и отменяет токены отмены,
|
||||
/// связанные с текущей операцией перетаскивания.
|
||||
/// </remarks>
|
||||
protected virtual void Reset()
|
||||
{
|
||||
_isDragging = false;
|
||||
_dragStartPosition = default;
|
||||
|
||||
_dragCancellationTokenSource?.Dispose();
|
||||
_dragCancellationTokenSource = null;
|
||||
}
|
||||
|
||||
#region IDragSource Implementation
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract Task<(bool CanStart, DragInfo? DragInfo)> CanStartDragAsync(CancellationToken ct = default);
|
||||
public abstract Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<bool> StartDragAsync(DragInfo dragInfo, CancellationToken ct = default)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task DragCompletedAsync(DragInfo dragInfo, Core.DragDrop.Enums.DragDropEffects effects, CancellationToken ct = default)
|
||||
public async Task OnDragCompletedAsync(DragInfo dragInfo, Lattice.Core.DragDrop.Enums.DragDropEffects effects, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_isDragging = false;
|
||||
OnDragCompleted(dragInfo, effects);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task DragCancelledAsync(DragInfo dragInfo, CancellationToken ct = default)
|
||||
public async Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_isDragging = false;
|
||||
OnDragCancelled(dragInfo);
|
||||
@@ -224,18 +340,27 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
#region Virtual Methods for Derived Classes
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при успешном завершении перетаскивания.
|
||||
/// Вызывается при успешном завершении операции перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="dragInfo">Информация о перетаскивании.</param>
|
||||
/// <param name="effects">Примененные эффекты.</param>
|
||||
protected virtual void OnDragCompleted(DragInfo dragInfo, Core.DragDrop.Enums.DragDropEffects effects)
|
||||
/// <param name="dragInfo">Информация о перетаскивании, использованная в операции.</param>
|
||||
/// <param name="effects">Эффекты, примененные при завершении операции.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы могут переопределить этот метод для выполнения
|
||||
/// дополнительных действий после успешного завершения перетаскивания,
|
||||
/// например, удаления исходного элемента при перемещении.
|
||||
/// </remarks>
|
||||
protected virtual void OnDragCompleted(DragInfo dragInfo, Lattice.Core.DragDrop.Enums.DragDropEffects effects)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при отмене перетаскивания.
|
||||
/// Вызывается при отмене операции перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="dragInfo">Информация о перетаскивании.</param>
|
||||
/// <param name="dragInfo">Информация о перетаскивании, использованная в операции.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы могут переопределить этот метод для выполнения
|
||||
/// действий по восстановлению состояния после отмены перетаскивания.
|
||||
/// </remarks>
|
||||
protected virtual void OnDragCancelled(DragInfo dragInfo)
|
||||
{
|
||||
}
|
||||
@@ -243,11 +368,16 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Освобождает ресурсы.
|
||||
/// Открепляет поведение от элемента и освобождает ресурсы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// После вызова этого метода поведение больше не будет обрабатывать события
|
||||
/// элемента и может быть безопасно удалено.
|
||||
/// </remarks>
|
||||
public virtual void Detach()
|
||||
{
|
||||
DetachFromElement();
|
||||
_associatedElement = null;
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,20 @@ using System.Threading.Tasks;
|
||||
namespace Lattice.UI.DragDrop.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// Базовый класс поведения цели сброса.
|
||||
/// Базовый класс поведения цели сброса для UI элементов.
|
||||
/// </summary>
|
||||
/// <typeparam name="TElement">Тип UI элемента.</typeparam>
|
||||
/// <typeparam name="TElement">Тип UI элемента, к которому прикрепляется поведение.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот класс предоставляет базовую реализацию поведения цели сброса для UI элементов.
|
||||
/// Он автоматически регистрирует элемент в сервисе перетаскивания, обновляет его границы
|
||||
/// при изменении размера или позиции и предоставляет методы для обработки событий сброса.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Производные классы должны реализовать абстрактные методы для конкретной
|
||||
/// UI-платформы и предоставить логику проверки и обработки сбрасываемых данных.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
where TElement : class
|
||||
{
|
||||
@@ -22,8 +33,12 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
private Rect _currentBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает связанный элемент.
|
||||
/// Получает или задает связанный UI элемент.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Элемент UI, к которому прикреплено поведение цели сброса.
|
||||
/// При изменении значения автоматически выполняется перерегистрация в сервисе перетаскивания.
|
||||
/// </value>
|
||||
protected TElement? AssociatedElement
|
||||
{
|
||||
get => _associatedElement;
|
||||
@@ -41,16 +56,28 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// <summary>
|
||||
/// Получает или задает приоритет цели сброса.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Цели с более высоким приоритетом проверяются первыми при нахождении курсора
|
||||
/// в области нескольких целей. Значение по умолчанию: 0.
|
||||
/// </value>
|
||||
public int Priority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает группу цели сброса.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя группы для группового управления целями сброса. Может использоваться
|
||||
/// для массовой отмены регистрации целей или применения общих настроек.
|
||||
/// </value>
|
||||
public string? Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает сервис перетаскивания.
|
||||
/// Получает сервис перетаскивания из контейнера зависимостей.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDragDropService"/>, используемый для регистрации цели сброса.
|
||||
/// При первом обращении выполняется получение сервиса из <see cref="ServiceProvider"/>.
|
||||
/// </value>
|
||||
protected IDragDropService DragDropService
|
||||
{
|
||||
get
|
||||
@@ -64,27 +91,47 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает провайдер сервисов.
|
||||
/// Получает провайдер сервисов для разрешения зависимостей.
|
||||
/// </summary>
|
||||
protected IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущие границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Прямоугольник, описывающий границы элемента в экранных координатах.
|
||||
/// Значение автоматически обновляется при изменении размера или позиции элемента.
|
||||
/// </value>
|
||||
protected Rect CurrentBounds => _currentBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Получает уникальный идентификатор регистрации цели в сервисе перетаскивания.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор, возвращенный методом <see cref="IDragDropService.RegisterDropTarget"/>,
|
||||
/// или null, если цель не зарегистрирована.
|
||||
/// </value>
|
||||
protected string? RegistrationId => _registrationId;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DropTargetBehaviorBase{TElement}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Провайдер сервисов.</param>
|
||||
/// <param name="serviceProvider">Провайдер сервисов для разрешения зависимостей.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="serviceProvider"/> равен null.
|
||||
/// </exception>
|
||||
protected DropTargetBehaviorBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при прикреплении к элементу.
|
||||
/// Вызывается при прикреплении поведения к элементу.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализация по умолчанию подписывается на события элемента, обновляет границы
|
||||
/// и регистрирует цель в сервисе перетаскивания.
|
||||
/// </remarks>
|
||||
protected virtual void AttachToElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
@@ -96,8 +143,12 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при откреплении от элемента.
|
||||
/// Вызывается при откреплении поведения от элемента.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализация по умолчанию отписывается от событий элемента и отменяет
|
||||
/// регистрацию цели в сервисе перетаскивания.
|
||||
/// </remarks>
|
||||
protected virtual void DetachFromElement()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
@@ -108,20 +159,32 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Подписывается на события элемента.
|
||||
/// Подписывается на события элемента, необходимые для отслеживания изменений размера и позиции.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <param name="element">Элемент, к событиям которого нужно подписаться.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для подписки на события конкретной
|
||||
/// UI-платформы (например, SizeChanged, LayoutUpdated для WPF).
|
||||
/// </remarks>
|
||||
protected abstract void SubscribeToEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Отписывается от событий элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <param name="element">Элемент, от событий которого нужно отписаться.</param>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для корректной отписки
|
||||
/// от событий, на которые была выполнена подписка в <see cref="SubscribeToEvents"/>.
|
||||
/// </remarks>
|
||||
protected abstract void UnsubscribeFromEvents(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот метод вызывается при изменении размера или позиции элемента для
|
||||
/// обновления области, в которой цель может принимать сбрасываемые данные.
|
||||
/// </remarks>
|
||||
protected virtual void UpdateBounds()
|
||||
{
|
||||
if (_associatedElement != null)
|
||||
@@ -139,13 +202,27 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// <summary>
|
||||
/// Получает границы элемента в экранных координатах.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент.</param>
|
||||
/// <returns>Границы в экранных координатах.</returns>
|
||||
/// <param name="element">Элемент, границы которого нужно получить.</param>
|
||||
/// <returns>Границы элемента в экранных координатах.</returns>
|
||||
/// <remarks>
|
||||
/// Производные классы должны реализовать этот метод для получения границ
|
||||
/// элемента в соответствии с конкретной UI-платформой.
|
||||
/// </remarks>
|
||||
protected abstract Rect GetScreenBounds(TElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует цель в сервисе перетаскивания.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод регистрирует текущий объект как цель сброса в сервисе перетаскивания
|
||||
/// с указанными приоритетом и группой.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Регистрация выполняется только если поведение прикреплено к элементу и
|
||||
/// цель еще не зарегистрирована.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual void RegisterToService()
|
||||
{
|
||||
if (_associatedElement != null && _registrationId == null)
|
||||
@@ -158,6 +235,10 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// <summary>
|
||||
/// Отменяет регистрацию цели в сервисе перетаскивания.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот метод отменяет регистрацию цели сброса, освобождая ресурсы
|
||||
/// в сервисе перетаскивания и предотвращая дальнейшую обработку событий.
|
||||
/// </remarks>
|
||||
protected virtual void UnregisterFromService()
|
||||
{
|
||||
if (_registrationId != null)
|
||||
@@ -170,6 +251,10 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// <summary>
|
||||
/// Вызывается при изменении размера или позиции элемента.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Производные классы должны вызывать этот метод из обработчиков событий
|
||||
/// изменения размера или позиции элемента для обновления границ цели.
|
||||
/// </remarks>
|
||||
protected virtual void OnElementLayoutChanged()
|
||||
{
|
||||
UpdateBounds();
|
||||
@@ -181,7 +266,7 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
public abstract Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken ct = default);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task DragOverAsync(DropInfo dropInfo, CancellationToken ct = default)
|
||||
public virtual async Task OnDragOverAsync(DropInfo dropInfo, CancellationToken ct = default)
|
||||
{
|
||||
// Базовая реализация устанавливает эффект по умолчанию
|
||||
if (await CanAcceptDropAsync(dropInfo))
|
||||
@@ -207,22 +292,58 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract Task DropAsync(DropInfo dropInfo, CancellationToken ct = default);
|
||||
public abstract Task OnDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task DragLeaveAsync(CancellationToken ct = default)
|
||||
public virtual Task OnDragLeaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Базовая реализация не делает ничего
|
||||
// Базовая реализация не выполняет действий при выходе курсора из области цели
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Освобождает ресурсы.
|
||||
/// Открепляет поведение от элемента и освобождает все связанные ресурсы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод выполняет следующие действия:
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Отписывается от всех событий связанного элемента</item>
|
||||
/// <item>Отменяет регистрацию цели в сервисе перетаскивания</item>
|
||||
/// <item>Освобождает ссылку на связанный элемент</item>
|
||||
/// <item>Очищает все временные данные и состояние</item>
|
||||
/// </list>
|
||||
/// <para>
|
||||
/// После вызова этого метода поведение больше не будет обрабатывать события
|
||||
/// элемента и не будет реагировать на операции перетаскивания. Поведение
|
||||
/// можно безопасно удалить после вызова этого метода.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <strong>Важно:</strong> Этот метод должен быть вызван перед удалением
|
||||
/// элемента из визуального дерева или перед заменой поведения, чтобы
|
||||
/// предотвратить утечки памяти и непредсказуемое поведение системы.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // Пример использования
|
||||
/// var dropBehavior = new MyDropTargetBehavior(serviceProvider);
|
||||
/// dropBehavior.AssociatedElement = myElement;
|
||||
///
|
||||
/// // ... использование поведения ...
|
||||
///
|
||||
/// // Перед удалением элемента или поведения
|
||||
/// dropBehavior.Detach();
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public virtual void Detach()
|
||||
{
|
||||
DetachFromElement();
|
||||
_associatedElement = null;
|
||||
_registrationId = null;
|
||||
_currentBounds = default;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user