using Lattice.Core.DragDrop.Abstractions;
using Lattice.Core.DragDrop.Enums;
using Lattice.Core.DragDrop.Models;
namespace Lattice.Core.DragDrop.Utilities;
///
/// Предоставляет утилитарные методы и фабричные методы для работы с системой перетаскивания с поддержкой async.
///
public static class AsyncDragDropUtilities
{
///
/// Создает асинхронную реализацию источника перетаскивания.
///
public static IDragSource CreateAsyncDragSource(
Func> dataProviderAsync,
Func>? canDragAsync = null,
Func? onCompletedAsync = null,
Func? onCancelledAsync = null)
{
return new AsyncDragSourceWrapper(dataProviderAsync, canDragAsync, onCompletedAsync, onCancelledAsync);
}
///
/// Создает асинхронную реализацию цели сброса.
///
public static IDropTarget CreateAsyncDropTarget(
Func>? canAcceptAsync = null,
Func? onDragOverAsync = null,
Func? onDropAsync = null,
Func? onDragLeaveAsync = null)
{
return new AsyncDropTargetWrapper(canAcceptAsync, onDragOverAsync, onDropAsync, onDragLeaveAsync);
}
#region Factory Methods
///
/// Создает информацию о перетаскивании.
///
public static Models.DragInfo CreateDragInfo(
object data,
Geometry.Point startPosition,
Enums.DragDropEffects allowedEffects = Enums.DragDropEffects.Copy | Enums.DragDropEffects.Move,
object? source = null,
Dictionary? parameters = null)
{
var dragInfo = new Models.DragInfo(data, allowedEffects, startPosition, source);
if (parameters != null)
{
foreach (var param in parameters)
{
dragInfo.SetParameter(param.Key, param.Value);
}
}
return dragInfo;
}
#endregion
#region Обертки-реализации
///
/// Обертка для создания асинхронного источника перетаскивания.
///
private sealed class AsyncDragSourceWrapper : IDragSource
{
private readonly Func> _dataProviderAsync;
private readonly Func>? _canDragAsync;
private readonly Func? _onCompletedAsync;
private readonly Func? _onCancelledAsync;
public AsyncDragSourceWrapper(
Func> dataProviderAsync,
Func>? canDragAsync = null,
Func? onCompletedAsync = null,
Func? onCancelledAsync = null)
{
_dataProviderAsync = dataProviderAsync ?? throw new ArgumentNullException(nameof(dataProviderAsync));
_canDragAsync = canDragAsync;
_onCompletedAsync = onCompletedAsync;
_onCancelledAsync = onCancelledAsync;
}
public async Task<(bool CanStart, DragInfo? DragInfo)> CanStartDragAsync(CancellationToken cancellationToken = default)
{
try
{
// Проверяем, может ли начаться перетаскивание
var canDrag = _canDragAsync != null ? await _canDragAsync().ConfigureAwait(false) : true;
if (!canDrag)
return (false, null);
// Получаем данные
var data = await _dataProviderAsync().ConfigureAwait(false);
if (data == null)
return (false, null);
// Создаем информацию о перетаскивании
var dragInfo = CreateDragInfo(
data,
Geometry.Point.Zero,
DragDropEffects.Copy | DragDropEffects.Move,
this);
return (true, dragInfo);
}
catch
{
return (false, null);
}
}
public Task StartDragAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
{
// Базовая реализация всегда разрешает начало
return Task.FromResult(true);
}
public async Task DragCompletedAsync(DragInfo dragInfo, DragDropEffects effects, CancellationToken cancellationToken = default)
{
if (_onCompletedAsync != null)
{
await _onCompletedAsync(dragInfo, effects).ConfigureAwait(false);
}
}
public async Task DragCancelledAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
{
if (_onCancelledAsync != null)
{
await _onCancelledAsync(dragInfo).ConfigureAwait(false);
}
}
}
///
/// Обертка для создания асинхронной цели сброса.
///
private sealed class AsyncDropTargetWrapper : IDropTarget
{
private readonly Func>? _canAcceptAsync;
private readonly Func? _onDragOverAsync;
private readonly Func? _onDropAsync;
private readonly Func? _onDragLeaveAsync;
public AsyncDropTargetWrapper(
Func>? canAcceptAsync = null,
Func? onDragOverAsync = null,
Func? onDropAsync = null,
Func? onDragLeaveAsync = null)
{
_canAcceptAsync = canAcceptAsync;
_onDragOverAsync = onDragOverAsync;
_onDropAsync = onDropAsync;
_onDragLeaveAsync = onDragLeaveAsync;
}
public async Task CanAcceptDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
{
try
{
if (_canAcceptAsync != null)
{
return await _canAcceptAsync(dropInfo).ConfigureAwait(false);
}
return true; // По умолчанию принимаем все
}
catch
{
return false; // При ошибке не принимаем
}
}
public async Task DragOverAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
{
try
{
if (_onDragOverAsync != null)
{
await _onDragOverAsync(dropInfo).ConfigureAwait(false);
}
}
catch
{
// Игнорируем ошибки в обработчике
}
}
public async Task DropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
{
try
{
if (_onDropAsync != null)
{
await _onDropAsync(dropInfo).ConfigureAwait(false);
}
}
catch
{
// Игнорируем ошибки в обработчике
}
}
public async Task DragLeaveAsync(CancellationToken cancellationToken = default)
{
try
{
if (_onDragLeaveAsync != null)
{
await _onDragLeaveAsync().ConfigureAwait(false);
}
}
catch
{
// Игнорируем ошибки в обработчике
}
}
}
#endregion
}