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 }