Отказ от DI и добавление фабрик
This commit is contained in:
581
Lattice.Core.DragDrop/Factories/DragDropFactory.cs
Normal file
581
Lattice.Core.DragDrop/Factories/DragDropFactory.cs
Normal file
@@ -0,0 +1,581 @@
|
||||
using Lattice.Core.DragDrop.Abstractions;
|
||||
using Lattice.Core.DragDrop.Enums;
|
||||
using Lattice.Core.DragDrop.Models;
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.Core.Geometry;
|
||||
|
||||
namespace Lattice.Core.DragDrop.Factories;
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика для создания компонентов системы перетаскивания.
|
||||
/// Предоставляет методы для создания сервисов, источников и целей перетаскивания.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Эта фабрика позволяет создавать компоненты системы перетаскивания без использования
|
||||
/// Dependency Injection, предоставляя простой и понятный API для наиболее распространенных сценариев.
|
||||
/// </remarks>
|
||||
public static class DragDropFactory
|
||||
{
|
||||
#region Сервисы перетаскивания
|
||||
|
||||
/// <summary>
|
||||
/// Создает новый экземпляр сервиса перетаскивания с настройками по умолчанию.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragDropService"/> с настройками по умолчанию.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Созданный сервис имеет следующие настройки по умолчанию:
|
||||
/// <list type="bullet">
|
||||
/// <item>Порог начала перетаскивания: 3.0 пикселей</item>
|
||||
/// <item>Таймаут асинхронных операций: 5000 миллисекунд</item>
|
||||
/// <item>Асинхронные операции: включены</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static IDragDropService CreateDragDropService()
|
||||
{
|
||||
return new DragDropService();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает новый экземпляр сервиса перетаскивания с пользовательскими настройками.
|
||||
/// </summary>
|
||||
/// <param name="configure">
|
||||
/// Делегат для настройки опций сервиса. Передает экземпляр <see cref="DragDropServiceOptions"/>
|
||||
/// для настройки параметров.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Настроенный экземпляр <see cref="IDragDropService"/>.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var service = DragDropFactory.CreateDragDropService(options =>
|
||||
/// {
|
||||
/// options.DragStartThreshold = 5.0;
|
||||
/// options.AsyncOperationTimeout = 3000;
|
||||
/// options.EnableAsyncOperations = true;
|
||||
/// });
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static IDragDropService CreateDragDropService(Action<DragDropServiceOptions> configure)
|
||||
{
|
||||
var options = new DragDropServiceOptions();
|
||||
configure(options);
|
||||
|
||||
return new DragDropService
|
||||
{
|
||||
DragStartThreshold = options.DragStartThreshold,
|
||||
AsyncOperationTimeout = options.AsyncOperationTimeout,
|
||||
EnableAsyncOperations = options.EnableAsyncOperations
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает сервис перетаскивания, оптимизированный для сенсорных устройств.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragDropService"/> с увеличенным порогом перетаскивания.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод создает сервис с увеличенным порогом начала перетаскивания (10.0 пикселей),
|
||||
/// что уменьшает вероятность случайного начала перетаскивания при использовании сенсорного экрана.
|
||||
/// </remarks>
|
||||
public static IDragDropService CreateTouchOptimizedService()
|
||||
{
|
||||
return new DragDropService
|
||||
{
|
||||
DragStartThreshold = 10.0,
|
||||
AsyncOperationTimeout = 3000,
|
||||
EnableAsyncOperations = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает сервис перетаскивания для точных операций (графические редакторы, карты).
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragDropService"/> с уменьшенным порогом перетаскивания.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод создает сервис с минимальным порогом начала перетаскивания (1.0 пиксель),
|
||||
/// что позволяет начинать перетаскивание с максимальной точностью.
|
||||
/// </remarks>
|
||||
public static IDragDropService CreatePrecisionDragService()
|
||||
{
|
||||
return new DragDropService
|
||||
{
|
||||
DragStartThreshold = 1.0,
|
||||
AsyncOperationTimeout = 10000, // Больше времени для сложных операций
|
||||
EnableAsyncOperations = true
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Источники перетаскивания
|
||||
|
||||
/// <summary>
|
||||
/// Создает простой источник перетаскивания с фиксированными данными.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// Данные, которые будут перетаскиваться. Не может быть null.
|
||||
/// </param>
|
||||
/// <param name="allowedEffects">
|
||||
/// Разрешенные эффекты перетаскивания. По умолчанию разрешены копирование и перемещение.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragSource"/>, который всегда предоставляет указанные данные.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="data"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот источник подходит для случаев, когда данные для перетаскивания известны заранее
|
||||
/// и не изменяются в процессе операции.
|
||||
/// </remarks>
|
||||
public static IDragSource CreateSimpleSource(object data, DragDropEffects allowedEffects = DragDropEffects.Copy | DragDropEffects.Move)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
|
||||
return new SimpleDragSource(data, allowedEffects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает источник перетаскивания с отложенной загрузкой данных.
|
||||
/// </summary>
|
||||
/// <param name="dataFactory">
|
||||
/// Фабрика данных, которая будет вызвана при начале перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="canDragChecker">
|
||||
/// Функция проверки возможности начала перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="allowedEffects">
|
||||
/// Разрешенные эффекты перетаскивания.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragSource"/> с отложенной загрузкой данных.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот источник полезен, когда данные для перетаскивания дорого создавать заранее
|
||||
/// или зависят от контекста в момент начала операции.
|
||||
/// </remarks>
|
||||
public static IDragSource CreateLazySource(
|
||||
Func<object> dataFactory,
|
||||
Func<bool> canDragChecker = null,
|
||||
DragDropEffects allowedEffects = DragDropEffects.Copy | DragDropEffects.Move)
|
||||
{
|
||||
if (dataFactory == null)
|
||||
throw new ArgumentNullException(nameof(dataFactory));
|
||||
|
||||
return new LazyDragSource(dataFactory, canDragChecker, allowedEffects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает источник перетаскивания для коллекции элементов.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Тип элементов в коллекции.
|
||||
/// </typeparam>
|
||||
/// <param name="items">
|
||||
/// Коллекция элементов для перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="itemSelector">
|
||||
/// Функция выбора конкретного элемента для перетаскивания из коллекции.
|
||||
/// </param>
|
||||
/// <param name="allowedEffects">
|
||||
/// Разрешенные эффекты перетаскивания.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDragSource"/> для коллекции элементов.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот источник позволяет перетаскивать элементы из коллекции. Функция <paramref name="itemSelector"/>
|
||||
/// определяет, какой именно элемент из коллекции будет перетаскиваться в текущем контексте.
|
||||
/// </remarks>
|
||||
public static IDragSource CreateCollectionSource<T>(
|
||||
IEnumerable<T> items,
|
||||
Func<IEnumerable<T>, T> itemSelector,
|
||||
DragDropEffects allowedEffects = DragDropEffects.Copy | DragDropEffects.Move)
|
||||
{
|
||||
if (items == null)
|
||||
throw new ArgumentNullException(nameof(items));
|
||||
if (itemSelector == null)
|
||||
throw new ArgumentNullException(nameof(itemSelector));
|
||||
|
||||
return new CollectionDragSource<T>(items, itemSelector, allowedEffects);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Цели сброса
|
||||
|
||||
/// <summary>
|
||||
/// Создает простую цель сброса, которая принимает данные любого типа.
|
||||
/// </summary>
|
||||
/// <param name="onDrop">
|
||||
/// Обработчик, вызываемый при сбросе данных.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDropTarget"/>, который принимает любые данные.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта цель подходит для простых сценариев, когда не требуется валидация типа данных.
|
||||
/// </remarks>
|
||||
public static IDropTarget CreateSimpleTarget(Action<DropInfo> onDrop)
|
||||
{
|
||||
if (onDrop == null)
|
||||
throw new ArgumentNullException(nameof(onDrop));
|
||||
|
||||
return new SimpleDropTarget(onDrop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает цель сброса с фильтрацией по типу данных.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Тип данных, которые может принимать цель.
|
||||
/// </typeparam>
|
||||
/// <param name="onDrop">
|
||||
/// Обработчик, вызываемый при сбросе данных.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDropTarget"/>, который принимает только данные типа <typeparamref name="T"/>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта цель автоматически проверяет тип сбрасываемых данных и вызывает обработчик только
|
||||
/// если данные могут быть приведены к указанному типу.
|
||||
/// </remarks>
|
||||
public static IDropTarget CreateTypedTarget<T>(Action<T, DropInfo> onDrop) where T : class
|
||||
{
|
||||
if (onDrop == null)
|
||||
throw new ArgumentNullException(nameof(onDrop));
|
||||
|
||||
return new TypedDropTarget<T>(onDrop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает цель сброса с пользовательской логикой валидации.
|
||||
/// </summary>
|
||||
/// <param name="canAccept">
|
||||
/// Функция проверки возможности приема данных.
|
||||
/// </param>
|
||||
/// <param name="onDrop">
|
||||
/// Обработчик, вызываемый при сбросе данных.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDropTarget"/> с пользовательской логикой валидации.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта цель позволяет реализовать сложную логику валидации, выходящую за рамки простой проверки типа.
|
||||
/// </remarks>
|
||||
public static IDropTarget CreateConditionalTarget(Func<DropInfo, bool> canAccept, Action<DropInfo> onDrop)
|
||||
{
|
||||
if (canAccept == null)
|
||||
throw new ArgumentNullException(nameof(canAccept));
|
||||
if (onDrop == null)
|
||||
throw new ArgumentNullException(nameof(onDrop));
|
||||
|
||||
return new ConditionalDropTarget(canAccept, onDrop);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Вспомогательные методы
|
||||
|
||||
/// <summary>
|
||||
/// Создает стандартные эффекты перетаскивания на основе модификаторов клавиатуры.
|
||||
/// </summary>
|
||||
/// <param name="controlKey">
|
||||
/// Нажата ли клавиша Control.
|
||||
/// </param>
|
||||
/// <param name="shiftKey">
|
||||
/// Нажата ли клавиша Shift.
|
||||
/// </param>
|
||||
/// <param name="altKey">
|
||||
/// Нажата ли клавиша Alt.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see cref="DragDropEffects"/>, соответствующие комбинации клавиш.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Стандартная логика:
|
||||
/// <list type="bullet">
|
||||
/// <item>Control + Shift: Link</item>
|
||||
/// <item>Control: Copy</item>
|
||||
/// <item>Shift: Move</item>
|
||||
/// <item>Alt: Link</item>
|
||||
/// <item>Без модификаторов: Move</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static DragDropEffects GetEffectsFromKeys(bool controlKey, bool shiftKey, bool altKey)
|
||||
{
|
||||
return DragDropEffectsExtensions.GetEffectFromKeys(controlKey, shiftKey, altKey);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Опции для настройки сервиса перетаскивания.
|
||||
/// </summary>
|
||||
public class DragDropServiceOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает или задает порог начала перетаскивания в пикселях.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Минимальное расстояние, которое должен пройти курсор, чтобы началась операция перетаскивания.
|
||||
/// Значение по умолчанию: 3.0.
|
||||
/// </value>
|
||||
public double DragStartThreshold { get; set; } = Constants.DragDropConstants.DefaultDragThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает максимальное время ожидания асинхронных операций в миллисекундах.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Время в миллисекундах, после которого асинхронная операция будет прервана.
|
||||
/// Значение по умолчанию: 5000.
|
||||
/// </value>
|
||||
public int AsyncOperationTimeout { get; set; } = Constants.DragDropConstants.DefaultAsyncTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает значение, указывающее, включены ли асинхронные операции.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если асинхронные операции включены; в противном случае — false.
|
||||
/// Значение по умолчанию: true.
|
||||
/// </value>
|
||||
public bool EnableAsyncOperations { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает интервал автоматической очистки неиспользуемых целей в минутах.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Интервал в минутах, через который будут удаляться цели сброса, к которым не было обращений.
|
||||
/// Значение по умолчанию: 10.
|
||||
/// </value>
|
||||
public int CleanupInterval { get; set; } = Constants.DragDropConstants.TargetLifetimeMinutes;
|
||||
}
|
||||
|
||||
#region Внутренние реализации
|
||||
|
||||
internal class SimpleDragSource : IDragSource
|
||||
{
|
||||
private readonly object _data;
|
||||
private readonly DragDropEffects _allowedEffects;
|
||||
|
||||
public SimpleDragSource(object data, DragDropEffects allowedEffects)
|
||||
{
|
||||
_data = data ?? throw new ArgumentNullException(nameof(data));
|
||||
_allowedEffects = allowedEffects;
|
||||
}
|
||||
|
||||
public Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var dragInfo = new DragInfo(_data, _allowedEffects, startPosition, this);
|
||||
return Task.FromResult<DragInfo?>(dragInfo);
|
||||
}
|
||||
|
||||
public Task OnDragCompletedAsync(DragInfo dragInfo, DragDropEffects effects, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
internal class LazyDragSource : IDragSource
|
||||
{
|
||||
private readonly Func<object> _dataFactory;
|
||||
private readonly Func<bool> _canDragChecker;
|
||||
private readonly DragDropEffects _allowedEffects;
|
||||
|
||||
public LazyDragSource(Func<object> dataFactory, Func<bool> canDragChecker, DragDropEffects allowedEffects)
|
||||
{
|
||||
_dataFactory = dataFactory ?? throw new ArgumentNullException(nameof(dataFactory));
|
||||
_canDragChecker = canDragChecker ?? (() => true);
|
||||
_allowedEffects = allowedEffects;
|
||||
}
|
||||
|
||||
public Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!_canDragChecker())
|
||||
return Task.FromResult<DragInfo?>(null);
|
||||
|
||||
var data = _dataFactory();
|
||||
if (data == null)
|
||||
return Task.FromResult<DragInfo?>(null);
|
||||
|
||||
var dragInfo = new DragInfo(data, _allowedEffects, startPosition, this);
|
||||
return Task.FromResult<DragInfo?>(dragInfo);
|
||||
}
|
||||
|
||||
public Task OnDragCompletedAsync(DragInfo dragInfo, DragDropEffects effects, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CollectionDragSource<T> : IDragSource
|
||||
{
|
||||
private readonly IEnumerable<T> _items;
|
||||
private readonly Func<IEnumerable<T>, T> _itemSelector;
|
||||
private readonly DragDropEffects _allowedEffects;
|
||||
|
||||
public CollectionDragSource(IEnumerable<T> items, Func<IEnumerable<T>, T> itemSelector, DragDropEffects allowedEffects)
|
||||
{
|
||||
_items = items ?? throw new ArgumentNullException(nameof(items));
|
||||
_itemSelector = itemSelector ?? throw new ArgumentNullException(nameof(itemSelector));
|
||||
_allowedEffects = allowedEffects;
|
||||
}
|
||||
|
||||
public Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var selectedItem = _itemSelector(_items);
|
||||
if (selectedItem == null)
|
||||
return Task.FromResult<DragInfo?>(null);
|
||||
|
||||
var dragInfo = new DragInfo(selectedItem, _allowedEffects, startPosition, this);
|
||||
return Task.FromResult<DragInfo?>(dragInfo);
|
||||
}
|
||||
|
||||
public Task OnDragCompletedAsync(DragInfo dragInfo, DragDropEffects effects, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SimpleDropTarget : IDropTarget
|
||||
{
|
||||
private readonly Action<DropInfo> _onDrop;
|
||||
|
||||
public SimpleDropTarget(Action<DropInfo> onDrop)
|
||||
{
|
||||
_onDrop = onDrop ?? throw new ArgumentNullException(nameof(onDrop));
|
||||
}
|
||||
|
||||
public Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(dropInfo.Data != null);
|
||||
}
|
||||
|
||||
public Task OnDragOverAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data != null)
|
||||
{
|
||||
dropInfo.SuggestedEffects = DragDropEffects.Move;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data != null)
|
||||
{
|
||||
_onDrop(dropInfo);
|
||||
dropInfo.MarkAsHandled();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragLeaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TypedDropTarget<T> : IDropTarget where T : class
|
||||
{
|
||||
private readonly Action<T, DropInfo> _onDrop;
|
||||
|
||||
public TypedDropTarget(Action<T, DropInfo> onDrop)
|
||||
{
|
||||
_onDrop = onDrop ?? throw new ArgumentNullException(nameof(onDrop));
|
||||
}
|
||||
|
||||
public Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(dropInfo.Data is T);
|
||||
}
|
||||
|
||||
public Task OnDragOverAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data is T)
|
||||
{
|
||||
dropInfo.SuggestedEffects = DragDropEffects.Move;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data is T data)
|
||||
{
|
||||
_onDrop(data, dropInfo);
|
||||
dropInfo.MarkAsHandled();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragLeaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ConditionalDropTarget : IDropTarget
|
||||
{
|
||||
private readonly Func<DropInfo, bool> _canAccept;
|
||||
private readonly Action<DropInfo> _onDrop;
|
||||
|
||||
public ConditionalDropTarget(Func<DropInfo, bool> canAccept, Action<DropInfo> onDrop)
|
||||
{
|
||||
_canAccept = canAccept ?? throw new ArgumentNullException(nameof(canAccept));
|
||||
_onDrop = onDrop ?? throw new ArgumentNullException(nameof(onDrop));
|
||||
}
|
||||
|
||||
public Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(_canAccept(dropInfo));
|
||||
}
|
||||
|
||||
public Task OnDragOverAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_canAccept(dropInfo))
|
||||
{
|
||||
dropInfo.SuggestedEffects = DragDropEffects.Move;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_canAccept(dropInfo))
|
||||
{
|
||||
_onDrop(dropInfo);
|
||||
dropInfo.MarkAsHandled();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnDragLeaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
474
Lattice.UI.DragDrop.WinUI/Factories/WinUIDragDropFactory.cs
Normal file
474
Lattice.UI.DragDrop.WinUI/Factories/WinUIDragDropFactory.cs
Normal file
@@ -0,0 +1,474 @@
|
||||
using Lattice.Core.DragDrop.Factories;
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.UI.DragDrop.WinUI.Behaviors;
|
||||
using Lattice.UI.DragDrop.WinUI.Controls;
|
||||
using Lattice.UI.DragDrop.WinUI.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
|
||||
namespace Lattice.UI.DragDrop.WinUI.Factories;
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика для создания компонентов системы перетаскивания WinUI.
|
||||
/// Предоставляет методы для быстрой настройки drag-and-drop в приложениях WinUI.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Эта фабрика упрощает интеграцию системы перетаскивания в WinUI приложения,
|
||||
/// предоставляя готовые методы для наиболее распространенных сценариев использования.
|
||||
/// </remarks>
|
||||
public static class WinUIDragDropFactory
|
||||
{
|
||||
#region Основные компоненты
|
||||
|
||||
/// <summary>
|
||||
/// Создает и инициализирует менеджер перетаскивания для WinUI окна.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Окно WinUI, для которого создается менеджер перетаскивания.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Инициализированный экземпляр <see cref="WinUIDragDropManager"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="window"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод создает менеджер перетаскивания и настраивает его для работы с указанным окном.
|
||||
/// Менеджер автоматически создает оверлей для визуальных элементов и подписывается на события.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public partial class MainWindow : Window
|
||||
/// {
|
||||
/// private WinUIDragDropManager _dragDropManager;
|
||||
///
|
||||
/// public MainWindow()
|
||||
/// {
|
||||
/// InitializeComponent();
|
||||
/// _dragDropManager = WinUIDragDropFactory.CreateManager(this);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static WinUIDragDropManager CreateManager(Window window)
|
||||
{
|
||||
if (window == null)
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
|
||||
var manager = WinUIDragDropManager.Instance;
|
||||
manager.Initialize(window);
|
||||
return manager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает и инициализирует менеджер перетаскивания с пользовательскими настройками.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Окно WinUI, для которого создается менеджер перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="configure">
|
||||
/// Делегат для настройки менеджера перед инициализацией.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Инициализированный экземпляр <see cref="WinUIDragDropManager"/>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод позволяет настроить параметры менеджера (например, смещение визуального элемента)
|
||||
/// перед его инициализацией.
|
||||
/// </remarks>
|
||||
public static WinUIDragDropManager CreateManager(Window window, Action<WinUIDragDropManager> configure)
|
||||
{
|
||||
if (window == null)
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
|
||||
var manager = WinUIDragDropManager.Instance;
|
||||
configure?.Invoke(manager);
|
||||
manager.Initialize(window);
|
||||
return manager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает хост для визуальных элементов перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Окно, к которому будет привязан хост.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="WinUIDragDropHost"/>, готовый к использованию.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Хост управляет отображением визуальных элементов (drag-визуализация, drop-превью)
|
||||
/// на оверлейном слое поверх основного содержимого окна.
|
||||
/// </remarks>
|
||||
public static WinUIDragDropHost CreateHost(Window window)
|
||||
{
|
||||
if (window == null)
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
|
||||
var host = new WinUIDragDropHost();
|
||||
host.Initialize(window);
|
||||
return host;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Поведения (Behaviors)
|
||||
|
||||
/// <summary>
|
||||
/// Создает поведение источника перетаскивания для элемента WinUI.
|
||||
/// </summary>
|
||||
/// <param name="dragDropService">
|
||||
/// Сервис перетаскивания, который будет управлять операциями.
|
||||
/// </param>
|
||||
/// <param name="host">
|
||||
/// Хост для отображения визуальных элементов.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="WinUIDragSourceBehavior"/>, готовый к прикреплению к элементу.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если любой из параметров равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Созданное поведение необходимо прикрепить к элементу с помощью метода <see cref="WinUIDragSourceBehavior.Attach"/>.
|
||||
/// </remarks>
|
||||
public static WinUIDragSourceBehavior CreateDragSourceBehavior(
|
||||
IDragDropService dragDropService,
|
||||
WinUIDragDropHost host)
|
||||
{
|
||||
if (dragDropService == null)
|
||||
throw new ArgumentNullException(nameof(dragDropService));
|
||||
if (host == null)
|
||||
throw new ArgumentNullException(nameof(host));
|
||||
|
||||
return new WinUIDragSourceBehavior(dragDropService, host);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает поведение цели сброса для элемента WinUI.
|
||||
/// </summary>
|
||||
/// <param name="dragDropService">
|
||||
/// Сервис перетаскивания, который будет управлять операциями.
|
||||
/// </param>
|
||||
/// <param name="host">
|
||||
/// Хост для отображения визуальных элементов.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="WinUIDropTargetBehavior"/>, готовый к прикреплению к элементу.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если любой из параметров равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Созданное поведение необходимо прикрепить к элементу с помощью метода <see cref="WinUIDropTargetBehavior.Attach"/>.
|
||||
/// </remarks>
|
||||
public static WinUIDropTargetBehavior CreateDropTargetBehavior(
|
||||
IDragDropService dragDropService,
|
||||
WinUIDragDropHost host)
|
||||
{
|
||||
if (dragDropService == null)
|
||||
throw new ArgumentNullException(nameof(dragDropService));
|
||||
if (host == null)
|
||||
throw new ArgumentNullException(nameof(host));
|
||||
|
||||
return new WinUIDropTargetBehavior(dragDropService, host);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Визуальные элементы
|
||||
|
||||
/// <summary>
|
||||
/// Создает визуальный элемент для отображения во время перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="dragData">
|
||||
/// Данные, которые будут отображены в визуальном элементе.
|
||||
/// </param>
|
||||
/// <param name="opacity">
|
||||
/// Прозрачность элемента (от 0.0 до 1.0).
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="DragAdorner"/>, настроенный для отображения указанных данных.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Созданный элемент можно использовать с методом <see cref="WinUIDragDropHost.ShowDragVisual"/>
|
||||
/// для отображения во время операции перетаскивания.
|
||||
/// </remarks>
|
||||
public static DragAdorner CreateDragAdorner(object dragData, double opacity = 0.8)
|
||||
{
|
||||
return new DragAdorner
|
||||
{
|
||||
DragData = dragData,
|
||||
Opacity = opacity
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает элемент предварительного просмотра для области сброса.
|
||||
/// </summary>
|
||||
/// <param name="color">
|
||||
/// Цвет подсветки области. Если не указан, используется цвет из ресурсов темы.
|
||||
/// </param>
|
||||
/// <param name="thickness">
|
||||
/// Толщина границы подсветки.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="DropPreviewAdorner"/>, готовый к отображению.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот элемент используется для визуального указания области, на которую можно сбросить данные.
|
||||
/// </remarks>
|
||||
public static DropPreviewAdorner CreateDropPreviewAdorner(
|
||||
Windows.UI.Color? color = null,
|
||||
double thickness = 2.0)
|
||||
{
|
||||
var adorner = new DropPreviewAdorner
|
||||
{
|
||||
PreviewThickness = thickness
|
||||
};
|
||||
|
||||
if (color.HasValue)
|
||||
{
|
||||
adorner.PreviewColor = color.Value;
|
||||
}
|
||||
|
||||
return adorner;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Готовые конфигурации для типовых сценариев
|
||||
|
||||
/// <summary>
|
||||
/// Создает полную систему перетаскивания для WinUI приложения.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Главное окно приложения.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Кортеж, содержащий менеджер перетаскивания и сервис перетаскивания.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод создает все необходимые компоненты для работы перетаскивания в приложении.
|
||||
/// Возвращаемый сервис можно использовать для создания дополнительных источников и целей.
|
||||
/// </remarks>
|
||||
public static (WinUIDragDropManager Manager, IDragDropService Service) CreateCompleteSystem(Window window)
|
||||
{
|
||||
var service = DragDropFactory.CreateDragDropService();
|
||||
var manager = CreateManager(window);
|
||||
return (manager, service);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает систему перетаскивания, оптимизированную для списков и коллекций.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Главное окно приложения.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Менеджер перетаскивания, настроенный для переупорядочивания элементов в списках.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта конфигурация устанавливает оптимальные параметры для перетаскивания элементов
|
||||
/// внутри списков (например, для изменения порядка элементов в ListView или ItemsControl).
|
||||
/// </remarks>
|
||||
public static WinUIDragDropManager CreateListReorderSystem(Window window)
|
||||
{
|
||||
var manager = CreateManager(window, m =>
|
||||
{
|
||||
m.DragVisualOffset = new Core.Geometry.Point(-15, -15);
|
||||
});
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает систему перетаскивания для файлов и документов.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Главное окно приложения.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Менеджер перетаскивания, настроенный для работы с файлами.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта конфигурация устанавливает увеличенный порог перетаскивания и специальные
|
||||
/// визуальные эффекты, характерные для операций с файлами.
|
||||
/// </remarks>
|
||||
public static WinUIDragDropManager CreateFileDragDropSystem(Window window)
|
||||
{
|
||||
var manager = CreateManager(window, m =>
|
||||
{
|
||||
m.DragVisualOffset = new Core.Geometry.Point(-25, -25);
|
||||
});
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает систему перетаскивания для графических редакторов и инструментов дизайна.
|
||||
/// </summary>
|
||||
/// <param name="window">
|
||||
/// Главное окно приложения.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Менеджер перетаскивания, настроенный для точного позиционирования.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Эта конфигурация уменьшает порог начала перетаскивания для более точного контроля
|
||||
/// и устанавливает минималистичную визуализацию.
|
||||
/// </remarks>
|
||||
public static WinUIDragDropManager CreateDesignToolSystem(Window window)
|
||||
{
|
||||
var manager = CreateManager(window, m =>
|
||||
{
|
||||
m.DragVisualOffset = new Core.Geometry.Point(-10, -10);
|
||||
});
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Вспомогательные методы
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает элемент как источник перетаскивания с использованием указанного менеджера.
|
||||
/// </summary>
|
||||
/// <param name="manager">
|
||||
/// Менеджер перетаскивания, который будет управлять операцией.
|
||||
/// </param>
|
||||
/// <param name="element">
|
||||
/// Элемент WinUI, который должен стать источником перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="dragData">
|
||||
/// Данные для перетаскивания. Если не указаны, будут использованы DataContext или Tag элемента.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Этот метод является оберткой вокруг <see cref="WinUIDragDropManager.MakeDragSource"/>,
|
||||
/// предоставляя более удобный API.
|
||||
/// </remarks>
|
||||
public static void SetupAsDragSource(WinUIDragDropManager manager, Microsoft.UI.Xaml.FrameworkElement element, object dragData = null)
|
||||
{
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
manager.MakeDragSource(element, dragData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает элемент как цель сброса с использованием указанного менеджера.
|
||||
/// </summary>
|
||||
/// <param name="manager">
|
||||
/// Менеджер перетаскивания, который будет управлять операцией.
|
||||
/// </param>
|
||||
/// <param name="element">
|
||||
/// Элемент WinUI, который должен стать целью сброса.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Этот метод является оберткой вокруг <see cref="WinUIDragDropManager.MakeDropTarget"/>,
|
||||
/// предоставляя более удобный API.
|
||||
/// </remarks>
|
||||
public static void SetupAsDropTarget(WinUIDragDropManager manager, Microsoft.UI.Xaml.FrameworkElement element)
|
||||
{
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
manager.MakeDropTarget(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает контейнер для поддержки переупорядочивания дочерних элементов.
|
||||
/// </summary>
|
||||
/// <param name="manager">
|
||||
/// Менеджер перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="container">
|
||||
/// Контейнер (например, StackPanel или Grid), дочерние элементы которого можно переупорядочивать.
|
||||
/// </param>
|
||||
/// <param name="childSelector">
|
||||
/// Функция для получения данных перетаскивания из дочернего элемента.
|
||||
/// Если не указана, используются DataContext дочерних элементов.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Этот метод автоматически настраивает все дочерние элементы контейнера как источники перетаскивания,
|
||||
/// а сам контейнер — как цель сброса, создавая функциональность переупорядочивания.
|
||||
/// </remarks>
|
||||
public static void SetupReorderContainer(
|
||||
WinUIDragDropManager manager,
|
||||
Microsoft.UI.Xaml.Controls.Panel container,
|
||||
Func<Microsoft.UI.Xaml.FrameworkElement, object> childSelector = null)
|
||||
{
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
if (container == null)
|
||||
throw new ArgumentNullException(nameof(container));
|
||||
|
||||
// Настраиваем контейнер как цель сброса
|
||||
manager.MakeDropTarget(container);
|
||||
|
||||
// Настраиваем все дочерние элементы как источники перетаскивания
|
||||
foreach (var child in container.Children)
|
||||
{
|
||||
if (child is Microsoft.UI.Xaml.FrameworkElement element)
|
||||
{
|
||||
var data = childSelector?.Invoke(element) ?? element.DataContext ?? element.Tag;
|
||||
manager.MakeDragSource(element, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Методы для работы с XAML
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает прикрепленные свойства для элемента источника перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="element">
|
||||
/// Элемент, который должен стать источником перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="dragData">
|
||||
/// Данные для перетаскивания.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Этот метод устанавливает attached properties, которые активируют поведение перетаскивания
|
||||
/// при использовании в XAML. Эквивалентно установке свойств IsDragSource и DragData в XAML.
|
||||
/// </remarks>
|
||||
public static void SetupDragSourceInXaml(Microsoft.UI.Xaml.FrameworkElement element, object dragData)
|
||||
{
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
// Устанавливаем attached properties
|
||||
element.SetValue(Behaviors.WinUIDragSourceBehavior.IsEnabledProperty, true);
|
||||
if (dragData != null)
|
||||
{
|
||||
element.SetValue(Behaviors.WinUIDragSourceBehavior.DragDataProperty, dragData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает прикрепленные свойства для элемента цели сброса.
|
||||
/// </summary>
|
||||
/// <param name="element">
|
||||
/// Элемент, который должен стать целью сброса.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Этот метод устанавливает attached properties, которые активируют поведение цели сброса
|
||||
/// при использовании в XAML. Эквивалентно установке свойства IsDropTarget в XAML.
|
||||
/// </remarks>
|
||||
public static void SetupDropTargetInXaml(Microsoft.UI.Xaml.FrameworkElement element)
|
||||
{
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
element.SetValue(Behaviors.WinUIDropTargetBehavior.IsEnabledProperty, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using Lattice.Core.DragDrop.Models;
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.Core.Geometry;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -59,24 +58,8 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDragDropService"/>, используемый для управления операциями перетаскивания.
|
||||
/// При первом обращении выполняется получение сервиса из <see cref="ServiceProvider"/>.
|
||||
/// </value>
|
||||
protected IDragDropService DragDropService
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dragDropService == null)
|
||||
{
|
||||
_dragDropService = ServiceProvider.GetRequiredService<IDragDropService>();
|
||||
}
|
||||
return _dragDropService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает провайдер сервисов для разрешения зависимостей.
|
||||
/// </summary>
|
||||
protected IServiceProvider ServiceProvider { get; }
|
||||
protected IDragDropService DragDropService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее, выполняется ли в данный момент операция перетаскивания.
|
||||
@@ -86,13 +69,13 @@ public abstract class DragSourceBehaviorBase<TElement> : IDragSource
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DragSourceBehaviorBase{TElement}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Провайдер сервисов для разрешения зависимостей.</param>
|
||||
/// <param name="dragDropService">Сервис перетаскивания.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="serviceProvider"/> равен null.
|
||||
/// Выбрасывается, когда <paramref name="dragDropService"/> равен null.
|
||||
/// </exception>
|
||||
protected DragSourceBehaviorBase(IServiceProvider serviceProvider)
|
||||
protected DragSourceBehaviorBase(IDragDropService dragDropService)
|
||||
{
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
DragDropService = dragDropService ?? throw new ArgumentNullException(nameof(dragDropService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Lattice.Core.DragDrop.Models;
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.Core.Geometry;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -76,24 +75,8 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDragDropService"/>, используемый для регистрации цели сброса.
|
||||
/// При первом обращении выполняется получение сервиса из <see cref="ServiceProvider"/>.
|
||||
/// </value>
|
||||
protected IDragDropService DragDropService
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dragDropService == null)
|
||||
{
|
||||
_dragDropService = ServiceProvider.GetRequiredService<IDragDropService>();
|
||||
}
|
||||
return _dragDropService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает провайдер сервисов для разрешения зависимостей.
|
||||
/// </summary>
|
||||
protected IServiceProvider ServiceProvider { get; }
|
||||
protected IDragDropService DragDropService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущие границы элемента в экранных координатах.
|
||||
@@ -116,13 +99,13 @@ public abstract class DropTargetBehaviorBase<TElement> : IDropTarget
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DropTargetBehaviorBase{TElement}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Провайдер сервисов для разрешения зависимостей.</param>
|
||||
/// <param name="dragDropService">Сервис перетаскивания.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, когда <paramref name="serviceProvider"/> равен null.
|
||||
/// Выбрасывается, когда <paramref name="dragDropService"/> равен null.
|
||||
/// </exception>
|
||||
protected DropTargetBehaviorBase(IServiceProvider serviceProvider)
|
||||
protected DropTargetBehaviorBase(IDragDropService dragDropService)
|
||||
{
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
DragDropService = dragDropService ?? throw new ArgumentNullException(nameof(dragDropService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.UI.DragDrop.Abstractions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Lattice.UI.DragDrop.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Методы расширения для регистрации сервисов перетаскивания в контейнере зависимостей.
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавляет сервисы перетаскивания в контейнер зависимостей.
|
||||
/// </summary>
|
||||
/// <param name="services">Коллекция сервисов для регистрации.</param>
|
||||
/// <returns>Коллекция сервисов с зарегистрированными сервисами перетаскивания.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод регистрирует основные сервисы перетаскивания, необходимые для работы системы:
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Основной сервис управления перетаскиванием (<see cref="IDragDropService"/>)</item>
|
||||
/// <item>Абстракции для визуального представления и обратной связи</item>
|
||||
/// <item>Провайдеры по умолчанию с безопасной реализацией</item>
|
||||
/// </list>
|
||||
/// <para>
|
||||
/// Для полноценной работы в конкретной UI-платформе (WPF, Avalonia, MAUI и т.д.)
|
||||
/// необходимо переопределить регистрации платформенными реализациями.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddLatticeDragDrop(this IServiceCollection services)
|
||||
{
|
||||
// Регистрация основного сервиса перетаскивания
|
||||
services.TryAddSingleton<IDragDropService, DragDropService>();
|
||||
|
||||
// Регистрация UI-специфичных абстракций с реализациями по умолчанию
|
||||
// Эти реализации безопасны (ничего не делают), но могут быть переопределены платформенными реализациями
|
||||
services.TryAddSingleton<IDragVisualProvider, DefaultDragVisualProvider>();
|
||||
services.TryAddSingleton<IDropVisualAdorner, DefaultDropVisualAdorner>();
|
||||
services.TryAddSingleton<IDragDropHost, DefaultDragDropHost>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет или заменяет реализацию поставщика визуального представления перетаскивания.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProvider">Тип поставщика визуального представления.</typeparam>
|
||||
/// <param name="services">Коллекция сервисов.</param>
|
||||
/// <returns>Коллекция сервисов.</returns>
|
||||
/// <remarks>
|
||||
/// Используйте этот метод для регистрации платформенной реализации поставщика визуального представления.
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddDragVisualProvider<TProvider>(this IServiceCollection services)
|
||||
where TProvider : class, IDragVisualProvider
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton<IDragVisualProvider, TProvider>());
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет или заменяет реализацию визуальной обратной связи для цели сброса.
|
||||
/// </summary>
|
||||
/// <typeparam name="TAdorner">Тип элемента визуальной обратной связи.</typeparam>
|
||||
/// <param name="services">Коллекция сервисов.</param>
|
||||
/// <returns>Коллекция сервисов.</returns>
|
||||
/// <remarks>
|
||||
/// Используйте этот метод для регистрации платформенной реализации визуальной обратной связи.
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddDropVisualAdorner<TAdorner>(this IServiceCollection services)
|
||||
where TAdorner : class, IDropVisualAdorner
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton<IDropVisualAdorner, TAdorner>());
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет или заменяет реализацию хоста для отображения визуальных элементов.
|
||||
/// </summary>
|
||||
/// <typeparam name="THost">Тип хоста визуальных элементов.</typeparam>
|
||||
/// <param name="services">Коллекция сервисов.</param>
|
||||
/// <returns>Коллекция сервисов.</returns>
|
||||
/// <remarks>
|
||||
/// Используйте этот метод для регистрации платформенной реализации хоста визуальных элементов.
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddDragDropHost<THost>(this IServiceCollection services)
|
||||
where THost : class, IDragDropHost
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton<IDragDropHost, THost>());
|
||||
return services;
|
||||
}
|
||||
|
||||
#region Default Implementations
|
||||
|
||||
/// <summary>
|
||||
/// Безопасная реализация поставщика визуального представления по умолчанию.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Эта реализация ничего не делает и используется как заглушка до тех пор,
|
||||
/// пока не будет предоставлена платформенная реализация.
|
||||
/// </remarks>
|
||||
private class DefaultDragVisualProvider : IDragVisualProvider
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public object? CreateDragVisual(Core.DragDrop.Models.DragInfo dragInfo, Core.Geometry.Point initialPosition)
|
||||
{
|
||||
// Безопасная реализация: не создает визуальное представление
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UpdateDragVisualPosition(object dragVisual, Core.Geometry.Point position)
|
||||
{
|
||||
// Ничего не делаем, так как визуальное представление не было создано
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ReleaseDragVisual(object dragVisual)
|
||||
{
|
||||
// Ничего не делаем, так как визуальное представление не было создано
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Безопасная реализация визуальной обратной связи по умолчанию.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Эта реализация ничего не делает и используется как заглушка до тех пор,
|
||||
/// пока не будет предоставлена платформенная реализация.
|
||||
/// </remarks>
|
||||
private class DefaultDropVisualAdorner : IDropVisualAdorner
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void Show(Core.DragDrop.Models.DropInfo dropInfo, Core.Geometry.Rect targetBounds)
|
||||
{
|
||||
// Безопасная реализация: не отображает визуальную обратную связь
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Update(Core.DragDrop.Models.DropInfo dropInfo)
|
||||
{
|
||||
// Ничего не делаем, так как обратная связь не отображается
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Hide()
|
||||
{
|
||||
// Ничего не делаем, так как обратная связь не отображается
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Безопасная реализация хоста визуальных элементов по умолчанию.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Эта реализация ничего не делает и используется как заглушка до тех пор,
|
||||
/// пока не будет предоставлена платформенная реализация.
|
||||
/// </remarks>
|
||||
private class DefaultDragDropHost : IDragDropHost
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void ShowDragVisual(object dragVisual, Core.Geometry.Point position)
|
||||
{
|
||||
// Безопасная реализация: не отображает визуальный элемент
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UpdateDragVisualPosition(object dragVisual, Core.Geometry.Point position)
|
||||
{
|
||||
// Ничего не делаем, так как визуальный элемент не отображается
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void HideDragVisual(object dragVisual)
|
||||
{
|
||||
// Ничего не делаем, так как визуальный элемент не отображается
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowDropAdorner(IDropVisualAdorner adorner)
|
||||
{
|
||||
// Безопасная реализация: не отображает обратную связь
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void HideDropAdorner(IDropVisualAdorner adorner)
|
||||
{
|
||||
// Ничего не делаем, так как обратная связь не отображается
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -13,8 +13,4 @@
|
||||
<ProjectReference Include="..\Lattice.Core.Geometry\Lattice.Core.Geometry.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,4 +1,5 @@
|
||||
<Solution>
|
||||
<Folder Name="/demo/" />
|
||||
<Folder Name="/src/" />
|
||||
<Folder Name="/src/Core/">
|
||||
<Project Path="Lattice.Core.Geometry/Lattice.Core.Geometry.csproj" Id="a84c6664-28fa-4082-9b91-6b2f3228ea53" />
|
||||
|
||||
Reference in New Issue
Block a user