Files
Lattice/Lattice.UI.DragDrop.WinUI/README.md

313 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lattice.Core.DragDrop
Библиотека для реализации drag-and-drop (перетаскивания) в приложениях на .NET.
## 📋 Обзор
Lattice.Core.DragDrop предоставляет полнофункциональную, асинхронную и потокобезопасную систему для реализации операций перетаскивания в пользовательских интерфейсах. Библиотека построена на принципах разделения ответственности и поддерживает сложные сценарии перетаскивания с минимальными усилиями со стороны разработчика.
### ✨ Основные возможности
-**Полностью асинхронный API** - все операции поддерживают async/await
-**Потокобезопасность** - безопасная работа в многопоточных средах
-**Расширяемая архитектура** - легко добавлять новые типы источников и целей
-**Подробные события** - полный контроль над жизненным циклом операций
-**Статистика и мониторинг** - встроенный сбор метрик использования
-**Поддержка CancellationToken** - корректная отмена длительных операций
-**Независимость от UI-фреймворков** - может использоваться с любым представлением
## 🏗️ Архитектура
### Основные компоненты
#### 1. **IDragSource**
Интерфейс для объектов, которые могут быть источником данных при перетаскивании. Определяет:
- Возможность начала перетаскивания
- Подготовку данных для передачи
- Реакцию на завершение или отмену операции
#### 2. **IDropTarget**
Интерфейс для объектов, которые могут принимать сброшенные данные. Определяет:
- Проверку совместимости данных
- Визуальную обратную связь при наведении
- Обработку сброшенных данных
#### 3. **DragDropService**
Центральный сервис, координирующий все операции. Отвечает за:
- Регистрацию и управление целями сброса
- Оркестрацию жизненного цикла операций
- Распространение событий между компонентами
- Сбор статистики и обработку ошибок
#### 4. **Модели данных**
- **DragInfo** - информация о начале перетаскивания
- **DropInfo** - информация о потенциальном сбросе
- **DragDropEffects** - перечисление возможных эффектов
## 🚀 Быстрый старт
### 1. Установка
```csharp
// Пример регистрации в DI-контейнере
services.AddSingleton<IDragDropService, DragDropService>();
```
### 2. Создание источника перетаскивания
```csharp
public class ItemDragSource : IDragSource
{
private readonly Item _item;
public ItemDragSource(Item item)
{
_item = item;
}
public async Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken ct)
{
// Проверяем, можно ли начать перетаскивание
if (!_item.CanBeDragged)
return null;
// Создаем информацию о перетаскивании
return new DragInfo(
data: _item,
allowedEffects: DragDropEffects.Copy | DragDropEffects.Move,
startPosition: startPosition,
source: this
);
}
public async Task OnDragCompletedAsync(DragInfo dragInfo, DragDropEffects effects, CancellationToken ct)
{
if (effects == DragDropEffects.Move)
{
// Удаляем элемент при перемещении
await _repository.DeleteAsync(_item.Id, ct);
}
}
public Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken ct)
{
// Очистка ресурсов при отмене
return Task.CompletedTask;
}
}
```
### 3. Создание цели сброса
```csharp
public class ContainerDropTarget : IDropTarget
{
private readonly ObservableCollection<Item> _items;
public async Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken ct)
{
// Проверяем тип данных
if (dropInfo.Data is not Item item)
return false;
// Проверяем бизнес-правила
return await _validator.CanAddItemAsync(item, ct);
}
public async Task OnDragOverAsync(DropInfo dropInfo, CancellationToken ct)
{
// Обновляем визуальную обратную связь
dropInfo.SuggestedEffects = DragDropEffects.Move;
dropInfo.ShowVisualFeedback = true;
}
public async Task OnDropAsync(DropInfo dropInfo, CancellationToken ct)
{
var item = (Item)dropInfo.Data;
await _items.AddAsync(item, ct);
// Помечаем как обработанное
dropInfo.MarkAsHandled();
}
public Task OnDragLeaveAsync(CancellationToken ct)
{
// Очищаем визуальную обратную связь
return Task.CompletedTask;
}
}
```
### 4. Регистрация и использование сервиса
```csharp
public class MainViewModel
{
private readonly IDragDropService _dragDropService;
public MainViewModel(IDragDropService dragDropService)
{
_dragDropService = dragDropService;
// Регистрация цели сброса
_targetId = _dragDropService.RegisterDropTarget(
target: new ContainerDropTarget(_items),
bounds: new Rect(0, 0, 400, 300),
priority: 0,
group: "main-container"
);
// Подписка на события
_dragDropService.DragStarted += OnDragStarted;
_dragDropService.DragCompleted += OnDragCompleted;
_dragDropService.ErrorOccurred += OnError;
}
// Обработка мышиных событий
public async Task OnMouseDown(Point position)
{
var source = new ItemDragSource(selectedItem);
await _dragDropService.StartDragAsync(source, position);
}
public async Task OnMouseMove(Point position)
{
await _dragDropService.UpdateDragAsync(position);
}
public async Task OnMouseUp(Point position)
{
var effects = await _dragDropService.EndDragAsync(position);
// Обработка результатов
}
}
```
## 📊 Статистика и мониторинг
```csharp
// Получение статистики использования
var stats = _dragDropService.GetStats();
Console.WriteLine($"Всего операций: {stats.TotalDragOperations}");
Console.WriteLine($"Успешных сбросов: {stats.SuccessfulDrops}");
Console.WriteLine($"Отменено операций: {stats.CancelledOperations}");
Console.WriteLine($"Среднее время операции: {stats.AverageOperationTime}");
```
## ⚙️ Конфигурация
### Параметры сервиса
```csharp
// Настройка через свойства сервиса
_dragDropService.DragStartThreshold = 5.0; // Порог в пикселях
_dragDropService.EnableAsyncOperations = true;
_dragDropService.AsyncOperationTimeout = 3000; // 3 секунды
```
### Константы по умолчанию
Все значения по умолчанию определены в классе `DragDropConstants`:
- `DefaultDragThreshold`: 3.0 пикселей
- `DefaultAsyncTimeout`: 5000 миллисекунд
- `TargetLifetimeMinutes`: 10 минут
## 🔧 Расширенные сценарии
### Группировка целей сброса
```csharp
// Регистрация группы целей
_dragDropService.RegisterDropTarget(target1, bounds1, group: "panel");
_dragDropService.RegisterDropTarget(target2, bounds2, group: "panel");
// Массовая отмена регистрации
_dragDropService.UnregisterDropTargetsInGroup("panel");
```
### Обработка ошибок
```csharp
private void OnError(object sender, DragDropErrorEventArgs e)
{
_logger.LogError(e.Exception,
"Ошибка в операции {Operation}",
e.Operation);
// Уведомление пользователя
_notificationService.ShowError("Ошибка при перетаскивании");
}
```
### Кастомизация эффектов
```csharp
// Использование расширений для работы с эффектами
if (effects.CanCopy())
{
// Логика для копирования
}
if (effects.CanMove())
{
// Логика для перемещения
}
// Определение эффекта по модификаторам клавиш
var effect = DragDropEffectsExtensions.GetEffectFromKeys(
controlKey: Keyboard.IsControlDown,
shiftKey: Keyboard.IsShiftDown,
altKey: Keyboard.IsAltDown
);
```
## 📝 Best Practices
1. **Производительность**
- Методы `CanAcceptDropAsync` и `OnDragOverAsync` вызываются часто, оптимизируйте их
- Избегайте синхронных операций в обработчиках
- Используйте кэширование при проверке типов данных
2. **Безопасность**
- Всегда проверяйте тип данных в `CanAcceptDropAsync`
- Валидируйте бизнес-правила перед обработкой сброса
- Используйте CancellationToken для отмены длительных операций
3. **Пользовательский опыт**
- Предоставляйте визуальную обратную связь через `DropInfo.ShowVisualFeedback`
- Используйте `DropInfo.VisualFeedbackData` для кастомизации отображения
- Обрабатывайте отмену операций для очистки временных данных
## 🔄 Миграция
### С версии 1.x на 2.0
1. **Интерфейсы переименованы:**
- `CanStartDragAsync``TryStartDragAsync`
- `DragCompletedAsync``OnDragCompletedAsync`
- `DragCancelledAsync``OnDragCancelledAsync`
2. **Классы EventArgs объединены:**
- Все события наследуются от `DragEventArgs`
- Упрощена иерархия классов событий
3. **Удалены устаревшие компоненты:**
- `AsyncDragDropUtilities` удален
- `ServiceCollectionExtensions` удален
## 📄 Лицензия
Библиотека распространяется под лицензией MIT. Подробности см. в файле LICENSE.
## 🤝 Вклад в разработку
Мы приветствуем вклад в развитие библиотеки. Перед отправкой pull request ознакомьтесь с руководством по контрибьютингу.
## 🐛 Отчеты об ошибках
Для сообщения об ошибках используйте Issues на GitHub. Пожалуйста, указывайте:
- Версию библиотеки
- Шаги для воспроизведения
- Ожидаемое и фактическое поведение
- Пример кода для демонстрации проблемы