713 lines
23 KiB
C#
713 lines
23 KiB
C#
using Lattice.Core.DragDrop.Abstractions;
|
||
using Lattice.Core.DragDrop.Enums;
|
||
using Lattice.Core.DragDrop.Models;
|
||
|
||
namespace Lattice.Core.DragDrop.Utilities;
|
||
|
||
/// <summary>
|
||
/// Предоставляет утилитарные методы и фабричные методы для работы с системой перетаскивания с поддержкой async.
|
||
/// </summary>
|
||
public static class AsyncDragDropUtilities
|
||
{
|
||
/// <summary>
|
||
/// Создает асинхронную реализацию источника перетаскивания.
|
||
/// </summary>
|
||
public static IAsyncDragSource CreateAsyncDragSource(
|
||
Func<Task<object>> dataProviderAsync,
|
||
Func<Task<bool>>? canDragAsync = null,
|
||
Func<DragInfo, DragDropEffects, Task>? onCompletedAsync = null,
|
||
Func<DragInfo, Task>? onCancelledAsync = null)
|
||
{
|
||
return new AsyncDragSourceWrapper(dataProviderAsync, canDragAsync, onCompletedAsync, onCancelledAsync);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает асинхронную реализацию цели сброса.
|
||
/// </summary>
|
||
public static IAsyncDropTarget CreateAsyncDropTarget(
|
||
Func<DropInfo, Task<bool>>? canAcceptAsync = null,
|
||
Func<DropInfo, Task>? onDragOverAsync = null,
|
||
Func<DropInfo, Task>? onDropAsync = null,
|
||
Func<Task>? onDragLeaveAsync = null)
|
||
{
|
||
return new AsyncDropTargetWrapper(canAcceptAsync, onDragOverAsync, onDropAsync, onDragLeaveAsync);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает адаптер для преобразования синхронного источника в асинхронный.
|
||
/// </summary>
|
||
public static IAsyncDragSource CreateAsyncAdapter(IDragSource syncSource)
|
||
{
|
||
return new SyncToAsyncDragSourceAdapter(syncSource);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает адаптер для преобразования синхронной цели в асинхронную.
|
||
/// </summary>
|
||
public static IAsyncDropTarget CreateAsyncAdapter(IDropTarget syncTarget)
|
||
{
|
||
return new SyncToAsyncDropTargetAdapter(syncTarget);
|
||
}
|
||
|
||
#region Обертки-реализации
|
||
|
||
/// <summary>
|
||
/// Обертка для создания асинхронного источника перетаскивания.
|
||
/// </summary>
|
||
private sealed class AsyncDragSourceWrapper : IAsyncDragSource
|
||
{
|
||
private readonly Func<Task<object>> _dataProviderAsync;
|
||
private readonly Func<Task<bool>>? _canDragAsync;
|
||
private readonly Func<DragInfo, DragDropEffects, Task>? _onCompletedAsync;
|
||
private readonly Func<DragInfo, Task>? _onCancelledAsync;
|
||
|
||
public AsyncDragSourceWrapper(
|
||
Func<Task<object>> dataProviderAsync,
|
||
Func<Task<bool>>? canDragAsync = null,
|
||
Func<DragInfo, DragDropEffects, Task>? onCompletedAsync = null,
|
||
Func<DragInfo, Task>? onCancelledAsync = null)
|
||
{
|
||
_dataProviderAsync = dataProviderAsync ?? throw new ArgumentNullException(nameof(dataProviderAsync));
|
||
_canDragAsync = canDragAsync;
|
||
_onCompletedAsync = onCompletedAsync;
|
||
_onCancelledAsync = onCancelledAsync;
|
||
}
|
||
|
||
public async Task<(bool CanStart, DragInfo? DragInfo)> CanStartDragAsync()
|
||
{
|
||
try
|
||
{
|
||
// Проверяем, может ли начаться перетаскивание
|
||
if (_canDragAsync != null)
|
||
{
|
||
var canDrag = await _canDragAsync().ConfigureAwait(false);
|
||
if (!canDrag)
|
||
return (false, null);
|
||
}
|
||
|
||
// Получаем данные
|
||
var data = await _dataProviderAsync().ConfigureAwait(false);
|
||
if (data == null)
|
||
return (false, null);
|
||
|
||
// Создаем информацию о перетаскивании
|
||
var dragInfo = DragDropUtilities.CreateDragInfo(
|
||
data,
|
||
Geometry.Point.Zero,
|
||
DragDropEffects.Copy | DragDropEffects.Move,
|
||
this);
|
||
|
||
return (true, dragInfo);
|
||
}
|
||
catch
|
||
{
|
||
return (false, null);
|
||
}
|
||
}
|
||
|
||
public Task<bool> StartDragAsync(DragInfo dragInfo)
|
||
{
|
||
// Базовая реализация всегда разрешает начало
|
||
return Task.FromResult(true);
|
||
}
|
||
|
||
public async Task DragCompletedAsync(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
if (_onCompletedAsync != null)
|
||
{
|
||
await _onCompletedAsync(dragInfo, effects).ConfigureAwait(false);
|
||
}
|
||
}
|
||
|
||
public async Task DragCancelledAsync(DragInfo dragInfo)
|
||
{
|
||
if (_onCancelledAsync != null)
|
||
{
|
||
await _onCancelledAsync(dragInfo).ConfigureAwait(false);
|
||
}
|
||
}
|
||
|
||
#region Синхронная реализация (для IDragSource)
|
||
|
||
public bool CanStartDrag(out DragInfo? dragInfo)
|
||
{
|
||
// Для синхронного вызова используем Task.Result
|
||
var result = Task.Run(() => CanStartDragAsync()).GetAwaiter().GetResult();
|
||
dragInfo = result.DragInfo;
|
||
return result.CanStart;
|
||
}
|
||
|
||
public bool StartDrag(DragInfo dragInfo)
|
||
{
|
||
return Task.Run(() => StartDragAsync(dragInfo)).GetAwaiter().GetResult();
|
||
}
|
||
|
||
public void DragCompleted(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
Task.Run(() => DragCompletedAsync(dragInfo, effects)).Wait();
|
||
}
|
||
|
||
public void DragCancelled(DragInfo dragInfo)
|
||
{
|
||
Task.Run(() => DragCancelledAsync(dragInfo)).Wait();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обертка для создания асинхронной цели сброса.
|
||
/// </summary>
|
||
private sealed class AsyncDropTargetWrapper : IAsyncDropTarget
|
||
{
|
||
private readonly Func<DropInfo, Task<bool>>? _canAcceptAsync;
|
||
private readonly Func<DropInfo, Task>? _onDragOverAsync;
|
||
private readonly Func<DropInfo, Task>? _onDropAsync;
|
||
private readonly Func<Task>? _onDragLeaveAsync;
|
||
|
||
public AsyncDropTargetWrapper(
|
||
Func<DropInfo, Task<bool>>? canAcceptAsync = null,
|
||
Func<DropInfo, Task>? onDragOverAsync = null,
|
||
Func<DropInfo, Task>? onDropAsync = null,
|
||
Func<Task>? onDragLeaveAsync = null)
|
||
{
|
||
_canAcceptAsync = canAcceptAsync;
|
||
_onDragOverAsync = onDragOverAsync;
|
||
_onDropAsync = onDropAsync;
|
||
_onDragLeaveAsync = onDragLeaveAsync;
|
||
}
|
||
|
||
public async Task<bool> CanAcceptDropAsync(DropInfo dropInfo)
|
||
{
|
||
try
|
||
{
|
||
if (_canAcceptAsync != null)
|
||
{
|
||
return await _canAcceptAsync(dropInfo).ConfigureAwait(false);
|
||
}
|
||
return true; // По умолчанию принимаем все
|
||
}
|
||
catch
|
||
{
|
||
return false; // При ошибке не принимаем
|
||
}
|
||
}
|
||
|
||
public async Task DragOverAsync(DropInfo dropInfo)
|
||
{
|
||
try
|
||
{
|
||
if (_onDragOverAsync != null)
|
||
{
|
||
await _onDragOverAsync(dropInfo).ConfigureAwait(false);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// Игнорируем ошибки в обработчике
|
||
}
|
||
}
|
||
|
||
public async Task DropAsync(DropInfo dropInfo)
|
||
{
|
||
try
|
||
{
|
||
if (_onDropAsync != null)
|
||
{
|
||
await _onDropAsync(dropInfo).ConfigureAwait(false);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// Игнорируем ошибки в обработчике
|
||
}
|
||
}
|
||
|
||
public async Task DragLeaveAsync()
|
||
{
|
||
try
|
||
{
|
||
if (_onDragLeaveAsync != null)
|
||
{
|
||
await _onDragLeaveAsync().ConfigureAwait(false);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// Игнорируем ошибки в обработчике
|
||
}
|
||
}
|
||
|
||
#region Синхронная реализация (для IDropTarget)
|
||
|
||
public bool CanAcceptDrop(DropInfo dropInfo)
|
||
{
|
||
return Task.Run(() => CanAcceptDropAsync(dropInfo)).GetAwaiter().GetResult();
|
||
}
|
||
|
||
public void DragOver(DropInfo dropInfo)
|
||
{
|
||
Task.Run(() => DragOverAsync(dropInfo)).Wait();
|
||
}
|
||
|
||
public void Drop(DropInfo dropInfo)
|
||
{
|
||
Task.Run(() => DropAsync(dropInfo)).Wait();
|
||
}
|
||
|
||
public void DragLeave()
|
||
{
|
||
Task.Run(DragLeaveAsync).Wait();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// Адаптер для преобразования синхронного источника в асинхронный.
|
||
/// </summary>
|
||
private sealed class SyncToAsyncDragSourceAdapter : IAsyncDragSource
|
||
{
|
||
private readonly IDragSource _syncSource;
|
||
|
||
public SyncToAsyncDragSourceAdapter(IDragSource syncSource)
|
||
{
|
||
_syncSource = syncSource ?? throw new ArgumentNullException(nameof(syncSource));
|
||
}
|
||
|
||
public async Task<(bool CanStart, DragInfo? DragInfo)> CanStartDragAsync()
|
||
{
|
||
return await Task.Run(() =>
|
||
{
|
||
var canStart = _syncSource.CanStartDrag(out var dragInfo);
|
||
return (canStart, dragInfo);
|
||
}).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task<bool> StartDragAsync(DragInfo dragInfo)
|
||
{
|
||
return await Task.Run(() => _syncSource.StartDrag(dragInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragCompletedAsync(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
await Task.Run(() => _syncSource.DragCompleted(dragInfo, effects)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragCancelledAsync(DragInfo dragInfo)
|
||
{
|
||
await Task.Run(() => _syncSource.DragCancelled(dragInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
#region Синхронная реализация (делегируем синхронному источнику)
|
||
|
||
public bool CanStartDrag(out DragInfo? dragInfo)
|
||
{
|
||
return _syncSource.CanStartDrag(out dragInfo);
|
||
}
|
||
|
||
public bool StartDrag(DragInfo dragInfo)
|
||
{
|
||
return _syncSource.StartDrag(dragInfo);
|
||
}
|
||
|
||
public void DragCompleted(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
_syncSource.DragCompleted(dragInfo, effects);
|
||
}
|
||
|
||
public void DragCancelled(DragInfo dragInfo)
|
||
{
|
||
_syncSource.DragCancelled(dragInfo);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// Адаптер для преобразования синхронной цели в асинхронную.
|
||
/// </summary>
|
||
private sealed class SyncToAsyncDropTargetAdapter : IAsyncDropTarget
|
||
{
|
||
private readonly IDropTarget _syncTarget;
|
||
|
||
public SyncToAsyncDropTargetAdapter(IDropTarget syncTarget)
|
||
{
|
||
_syncTarget = syncTarget ?? throw new ArgumentNullException(nameof(syncTarget));
|
||
}
|
||
|
||
public async Task<bool> CanAcceptDropAsync(DropInfo dropInfo)
|
||
{
|
||
return await Task.Run(() => _syncTarget.CanAcceptDrop(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragOverAsync(DropInfo dropInfo)
|
||
{
|
||
await Task.Run(() => _syncTarget.DragOver(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DropAsync(DropInfo dropInfo)
|
||
{
|
||
await Task.Run(() => _syncTarget.Drop(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragLeaveAsync()
|
||
{
|
||
await Task.Run(() => _syncTarget.DragLeave()).ConfigureAwait(false);
|
||
}
|
||
|
||
#region Синхронная реализация (делегируем синхронной цели)
|
||
|
||
public bool CanAcceptDrop(DropInfo dropInfo)
|
||
{
|
||
return _syncTarget.CanAcceptDrop(dropInfo);
|
||
}
|
||
|
||
public void DragOver(DropInfo dropInfo)
|
||
{
|
||
_syncTarget.DragOver(dropInfo);
|
||
}
|
||
|
||
public void Drop(DropInfo dropInfo)
|
||
{
|
||
_syncTarget.Drop(dropInfo);
|
||
}
|
||
|
||
public void DragLeave()
|
||
{
|
||
_syncTarget.DragLeave();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Утилитарные методы
|
||
|
||
/// <summary>
|
||
/// Выполняет асинхронную операцию с таймаутом.
|
||
/// </summary>
|
||
public static async Task<T> ExecuteWithTimeoutAsync<T>(
|
||
Task<T> task,
|
||
TimeSpan timeout,
|
||
T defaultValue = default!)
|
||
{
|
||
if (timeout <= TimeSpan.Zero)
|
||
return await task.ConfigureAwait(false);
|
||
|
||
var delayTask = Task.Delay(timeout);
|
||
var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
|
||
|
||
if (completedTask == delayTask)
|
||
{
|
||
return defaultValue;
|
||
}
|
||
|
||
return await task.ConfigureAwait(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Выполняет асинхронную операцию с таймаутом.
|
||
/// </summary>
|
||
public static async Task<bool> ExecuteWithTimeoutAsync(
|
||
Task task,
|
||
TimeSpan timeout)
|
||
{
|
||
if (timeout <= TimeSpan.Zero)
|
||
{
|
||
await task.ConfigureAwait(false);
|
||
return true;
|
||
}
|
||
|
||
var delayTask = Task.Delay(timeout);
|
||
var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
|
||
|
||
return completedTask == task;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Выполняет асинхронную операцию с таймаутом и обработкой ошибок.
|
||
/// </summary>
|
||
public static async Task<T?> ExecuteSafeWithTimeoutAsync<T>(
|
||
Task<T> task,
|
||
TimeSpan timeout,
|
||
Func<Exception, T?> errorHandler = null) where T : class
|
||
{
|
||
try
|
||
{
|
||
if (timeout <= TimeSpan.Zero)
|
||
return await task.ConfigureAwait(false);
|
||
|
||
var delayTask = Task.Delay(timeout);
|
||
var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
|
||
|
||
if (completedTask == delayTask)
|
||
{
|
||
return default;
|
||
}
|
||
|
||
return await task.ConfigureAwait(false);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return errorHandler?.Invoke(ex) ?? default;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает комбинированный источник из синхронного и асинхронного.
|
||
/// </summary>
|
||
public static IAsyncDragSource Combine(
|
||
IDragSource syncSource,
|
||
IAsyncDragSource asyncSource,
|
||
bool preferAsync = true)
|
||
{
|
||
return new CombinedDragSource(syncSource, asyncSource, preferAsync);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает комбинированную цель из синхронной и асинхронной.
|
||
/// </summary>
|
||
public static IAsyncDropTarget Combine(
|
||
IDropTarget syncTarget,
|
||
IAsyncDropTarget asyncTarget,
|
||
bool preferAsync = true)
|
||
{
|
||
return new CombinedDropTarget(syncTarget, asyncTarget, preferAsync);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Комбинированные реализации
|
||
|
||
/// <summary>
|
||
/// Комбинированный источник, поддерживающий как синхронный, так и асинхронный API.
|
||
/// </summary>
|
||
private sealed class CombinedDragSource : IAsyncDragSource
|
||
{
|
||
private readonly IDragSource _syncSource;
|
||
private readonly IAsyncDragSource _asyncSource;
|
||
private readonly bool _preferAsync;
|
||
|
||
public CombinedDragSource(IDragSource syncSource, IAsyncDragSource asyncSource, bool preferAsync)
|
||
{
|
||
_syncSource = syncSource ?? throw new ArgumentNullException(nameof(syncSource));
|
||
_asyncSource = asyncSource ?? throw new ArgumentNullException(nameof(asyncSource));
|
||
_preferAsync = preferAsync;
|
||
}
|
||
|
||
public async Task<(bool CanStart, DragInfo? DragInfo)> CanStartDragAsync()
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
return await _asyncSource.CanStartDragAsync().ConfigureAwait(false);
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
// Используем синхронную версию в отдельной задаче
|
||
return await Task.Run(() =>
|
||
{
|
||
var canStart = _syncSource.CanStartDrag(out var dragInfo);
|
||
return (canStart, dragInfo);
|
||
}).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task<bool> StartDragAsync(DragInfo dragInfo)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
return await _asyncSource.StartDragAsync(dragInfo).ConfigureAwait(false);
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
return await Task.Run(() => _syncSource.StartDrag(dragInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragCompletedAsync(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
await _asyncSource.DragCompletedAsync(dragInfo, effects).ConfigureAwait(false);
|
||
return;
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
await Task.Run(() => _syncSource.DragCompleted(dragInfo, effects)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragCancelledAsync(DragInfo dragInfo)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
await _asyncSource.DragCancelledAsync(dragInfo).ConfigureAwait(false);
|
||
return;
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
await Task.Run(() => _syncSource.DragCancelled(dragInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
#region Синхронная реализация
|
||
|
||
public bool CanStartDrag(out DragInfo? dragInfo)
|
||
{
|
||
return _syncSource.CanStartDrag(out dragInfo);
|
||
}
|
||
|
||
public bool StartDrag(DragInfo dragInfo)
|
||
{
|
||
return _syncSource.StartDrag(dragInfo);
|
||
}
|
||
|
||
public void DragCompleted(DragInfo dragInfo, DragDropEffects effects)
|
||
{
|
||
_syncSource.DragCompleted(dragInfo, effects);
|
||
}
|
||
|
||
public void DragCancelled(DragInfo dragInfo)
|
||
{
|
||
_syncSource.DragCancelled(dragInfo);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// Комбинированная цель, поддерживающая как синхронный, так и асинхронный API.
|
||
/// </summary>
|
||
private sealed class CombinedDropTarget : IAsyncDropTarget
|
||
{
|
||
private readonly IDropTarget _syncTarget;
|
||
private readonly IAsyncDropTarget _asyncTarget;
|
||
private readonly bool _preferAsync;
|
||
|
||
public CombinedDropTarget(IDropTarget syncTarget, IAsyncDropTarget asyncTarget, bool preferAsync)
|
||
{
|
||
_syncTarget = syncTarget ?? throw new ArgumentNullException(nameof(syncTarget));
|
||
_asyncTarget = asyncTarget ?? throw new ArgumentNullException(nameof(asyncTarget));
|
||
_preferAsync = preferAsync;
|
||
}
|
||
|
||
public async Task<bool> CanAcceptDropAsync(DropInfo dropInfo)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
return await _asyncTarget.CanAcceptDropAsync(dropInfo).ConfigureAwait(false);
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
return await Task.Run(() => _syncTarget.CanAcceptDrop(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragOverAsync(DropInfo dropInfo)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
await _asyncTarget.DragOverAsync(dropInfo).ConfigureAwait(false);
|
||
return;
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
await Task.Run(() => _syncTarget.DragOver(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DropAsync(DropInfo dropInfo)
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
await _asyncTarget.DropAsync(dropInfo).ConfigureAwait(false);
|
||
return;
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
await Task.Run(() => _syncTarget.Drop(dropInfo)).ConfigureAwait(false);
|
||
}
|
||
|
||
public async Task DragLeaveAsync()
|
||
{
|
||
if (_preferAsync)
|
||
{
|
||
try
|
||
{
|
||
await _asyncTarget.DragLeaveAsync().ConfigureAwait(false);
|
||
return;
|
||
}
|
||
catch
|
||
{
|
||
// В случае ошибки пробуем синхронную версию
|
||
}
|
||
}
|
||
|
||
await Task.Run(() => _syncTarget.DragLeave()).ConfigureAwait(false);
|
||
}
|
||
|
||
#region Синхронная реализация
|
||
|
||
public bool CanAcceptDrop(DropInfo dropInfo)
|
||
{
|
||
return _syncTarget.CanAcceptDrop(dropInfo);
|
||
}
|
||
|
||
public void DragOver(DropInfo dropInfo)
|
||
{
|
||
_syncTarget.DragOver(dropInfo);
|
||
}
|
||
|
||
public void Drop(DropInfo dropInfo)
|
||
{
|
||
_syncTarget.Drop(dropInfo);
|
||
}
|
||
|
||
public void DragLeave()
|
||
{
|
||
_syncTarget.DragLeave();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#endregion
|
||
} |