Переработаны методы.
This commit is contained in:
@@ -1,547 +1,313 @@
|
||||
# Lattice.UI.DragDrop.WinUI
|
||||
# Lattice.Core.DragDrop
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
Библиотека для реализации drag-and-drop (перетаскивания) в приложениях на .NET.
|
||||
|
||||
Полнофункциональная реализация системы перетаскивания для WinUI 3 в составе Lattice UI Framework.
|
||||
## 📋 Обзор
|
||||
|
||||
## 🎉 Демо
|
||||
Lattice.Core.DragDrop предоставляет полнофункциональную, асинхронную и потокобезопасную систему для реализации операций перетаскивания в пользовательских интерфейсах. Библиотека построена на принципах разделения ответственности и поддерживает сложные сценарии перетаскивания с минимальными усилиями со стороны разработчика.
|
||||
|
||||

|
||||
### ✨ Основные возможности
|
||||
|
||||
*Перетаскивание элементов между контейнерами и переупорядочивание списка*
|
||||
- ✅ **Полностью асинхронный API** - все операции поддерживают async/await
|
||||
- ✅ **Потокобезопасность** - безопасная работа в многопоточных средах
|
||||
- ✅ **Расширяемая архитектура** - легко добавлять новые типы источников и целей
|
||||
- ✅ **Подробные события** - полный контроль над жизненным циклом операций
|
||||
- ✅ **Статистика и мониторинг** - встроенный сбор метрик использования
|
||||
- ✅ **Поддержка CancellationToken** - корректная отмена длительных операций
|
||||
- ✅ **Независимость от UI-фреймворков** - может использоваться с любым представлением
|
||||
|
||||
## 📦 Особенности
|
||||
## 🏗️ Архитектура
|
||||
|
||||
✅ **Готовое решение для WinUI 3** - работает из коробки
|
||||
✅ **Attached Behaviors** - легко подключается к любым UIElement
|
||||
✅ **Визуальная обратная связь** - анимации и подсветка
|
||||
✅ **Переупорядочивание элементов** - drag-and-drop в списках
|
||||
✅ **Кастомизация стилей** - полный контроль над внешним видом
|
||||
✅ **Поддержка сложных сценариев** - вложенные элементы, зоны сброса
|
||||
✅ **Производительность** - оптимизировано для плавной работы
|
||||
### Основные компоненты
|
||||
|
||||
#### 1. **IDragSource**
|
||||
Интерфейс для объектов, которые могут быть источником данных при перетаскивании. Определяет:
|
||||
- Возможность начала перетаскивания
|
||||
- Подготовку данных для передачи
|
||||
- Реакцию на завершение или отмену операции
|
||||
|
||||
#### 2. **IDropTarget**
|
||||
Интерфейс для объектов, которые могут принимать сброшенные данные. Определяет:
|
||||
- Проверку совместимости данных
|
||||
- Визуальную обратную связь при наведении
|
||||
- Обработку сброшенных данных
|
||||
|
||||
#### 3. **DragDropService**
|
||||
Центральный сервис, координирующий все операции. Отвечает за:
|
||||
- Регистрацию и управление целями сброса
|
||||
- Оркестрацию жизненного цикла операций
|
||||
- Распространение событий между компонентами
|
||||
- Сбор статистики и обработку ошибок
|
||||
|
||||
#### 4. **Модели данных**
|
||||
- **DragInfo** - информация о начале перетаскивания
|
||||
- **DropInfo** - информация о потенциальном сбросе
|
||||
- **DragDropEffects** - перечисление возможных эффектов
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### 1. Установка
|
||||
|
||||
Добавьте пакет через NuGet:
|
||||
|
||||
```powershell
|
||||
Install-Package Lattice.UI.DragDrop.WinUI
|
||||
```csharp
|
||||
// Пример регистрации в DI-контейнере
|
||||
services.AddSingleton<IDragDropService, DragDropService>();
|
||||
```
|
||||
|
||||
Или через Package Manager:
|
||||
|
||||
```xml
|
||||
<PackageReference Include="Lattice.UI.DragDrop.WinUI" Version="1.0.0" />
|
||||
```
|
||||
|
||||
### 2. Инициализация в приложении
|
||||
### 2. Создание источника перетаскивания
|
||||
|
||||
```csharp
|
||||
using Lattice.UI.DragDrop.WinUI.Extensions;
|
||||
using Lattice.UI.DragDrop.WinUI.Helpers;
|
||||
|
||||
public MainWindow()
|
||||
public class ItemDragSource : IDragSource
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Инициализация ресурсов
|
||||
ResourceHelper.InitializeDragDropResources();
|
||||
|
||||
// Настройка примеров перетаскивания
|
||||
SetupDragDropExamples();
|
||||
}
|
||||
private readonly Item _item;
|
||||
|
||||
private void SetupDragDropExamples()
|
||||
{
|
||||
// Пример 1: Перетаскивание текста
|
||||
var textBlock = new TextBlock { Text = "Перетащи меня" };
|
||||
textBlock.MakeDragSource("Пример данных");
|
||||
|
||||
// Пример 2: Цель сброса
|
||||
var border = new Border { Background = new SolidColorBrush(Colors.LightGray) };
|
||||
border.MakeDropTarget(typeof(string));
|
||||
|
||||
// Пример 3: Стилизация
|
||||
var button = new Button { Content = "Кнопка" };
|
||||
button.ApplyDragStyle();
|
||||
button.EnableDragVisualFeedback();
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 Использование
|
||||
|
||||
### Базовое перетаскивание
|
||||
|
||||
```csharp
|
||||
// Создаем перетаскиваемый элемент
|
||||
var dragSource = new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.LightBlue),
|
||||
Child = new TextBlock { Text = "Drag me" }
|
||||
};
|
||||
|
||||
// Делаем элемент перетаскиваемым
|
||||
dragSource.MakeDragSource(dragSource); // Можно передать любые данные
|
||||
|
||||
// Создаем цель сброса
|
||||
var dropTarget = new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.LightGreen)
|
||||
};
|
||||
|
||||
// Делаем элемент целью сброса
|
||||
dropTarget.MakeDropTarget(typeof(Border));
|
||||
```
|
||||
|
||||
### Переупорядочивание элементов в списке
|
||||
|
||||
```csharp
|
||||
// Создаем контейнер с поддержкой переупорядочивания
|
||||
var reorderContainer = new StackPanel();
|
||||
reorderContainer.MakeDropTarget(typeof(UIElement));
|
||||
|
||||
// Добавляем перетаскиваемые элементы
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var item = new Border
|
||||
public ItemDragSource(Item item)
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.White),
|
||||
BorderBrush = new SolidColorBrush(Colors.Gray),
|
||||
BorderThickness = new Thickness(1),
|
||||
Margin = new Thickness(0, 0, 0, 5),
|
||||
Child = new TextBlock { Text = $"Item {i + 1}" }
|
||||
};
|
||||
|
||||
item.MakeDragSource(item);
|
||||
reorderContainer.Children.Add(item);
|
||||
}
|
||||
```
|
||||
_item = item;
|
||||
}
|
||||
|
||||
### Кастомизация визуальной обратной связи
|
||||
|
||||
```csharp
|
||||
// Создаем кастомный стиль
|
||||
var customStyle = new Style(typeof(Control));
|
||||
customStyle.Setters.Add(new Setter(Control.BackgroundProperty,
|
||||
new SolidColorBrush(Colors.Yellow)));
|
||||
customStyle.Setters.Add(new Setter(Control.BorderBrushProperty,
|
||||
new SolidColorBrush(Colors.Red)));
|
||||
|
||||
// Применяем стиль к элементу
|
||||
var element = new Button { Content = "Custom Style" };
|
||||
element.SetDropFeedbackStyle(customStyle);
|
||||
element.MakeDragSource("data");
|
||||
```
|
||||
|
||||
## 📁 Структура API
|
||||
|
||||
### Behaviors (Поведения)
|
||||
|
||||
| Класс | Описание |
|
||||
|-------|----------|
|
||||
| `WinUIDragSourceBehavior` | Прикрепляемое поведение для источников |
|
||||
| `WinUIDropTargetBehavior` | Прикрепляемое поведение для целей |
|
||||
|
||||
### Controls (Контролы)
|
||||
|
||||
| Контрол | Назначение |
|
||||
|---------|------------|
|
||||
| `DragAdorner` | Визуальное представление перетаскивания |
|
||||
| `DropPreviewAdorner` | Предпросмотр области сброса |
|
||||
| `DragDropOverlay` | Оверлей для визуальных элементов |
|
||||
|
||||
### Services (Сервисы)
|
||||
|
||||
| Сервис | Назначение |
|
||||
|--------|------------|
|
||||
| `WinUIDragVisualProvider` | Создание визуальных элементов |
|
||||
| `DragDropConfigurationService` | Централизованная настройка |
|
||||
|
||||
### Extensions (Расширения)
|
||||
|
||||
```csharp
|
||||
// Основные методы расширения
|
||||
element.MakeDragSource(data); // Сделать перетаскиваемым
|
||||
element.MakeDropTarget(types); // Сделать целью сброса
|
||||
control.ApplyDragStyle(); // Применить стиль перетаскивания
|
||||
control.SetDragVisualState("Dragging"); // Установить визуальное состояние
|
||||
```
|
||||
|
||||
## 🎯 Примеры использования
|
||||
|
||||
### Пример 1: Файловый менеджер
|
||||
|
||||
```csharp
|
||||
// Перетаскивание файлов
|
||||
var fileItem = new ListViewItem { Content = "Document.pdf" };
|
||||
fileItem.MakeDragSource(new FileData { Path = "C:\\Files\\Document.pdf" });
|
||||
|
||||
// Папка - цель сброса
|
||||
var folderItem = new ListViewItem { Content = "Downloads" };
|
||||
folderItem.MakeDropTarget(typeof(FileData));
|
||||
folderItem.SetDropHandler(new FileDropHandler());
|
||||
```
|
||||
|
||||
### Пример 2: Конструктор UI
|
||||
|
||||
```csharp
|
||||
// Панель инструментов
|
||||
var toolbox = new StackPanel();
|
||||
toolbox.MakeChildrenDraggable(element => new ControlTemplate
|
||||
{
|
||||
Type = element.GetType(),
|
||||
Name = element.Name
|
||||
});
|
||||
|
||||
// Область дизайна
|
||||
var designArea = new Canvas();
|
||||
designArea.MakeDropTarget(typeof(ControlTemplate));
|
||||
|
||||
// Обработчик сброса
|
||||
designArea.Drop += (sender, e) =>
|
||||
{
|
||||
var template = e.DataView.GetData<ControlTemplate>();
|
||||
var control = Activator.CreateInstance(template.Type);
|
||||
Canvas.SetLeft(control, e.GetPosition(designArea).X);
|
||||
Canvas.SetTop(control, e.GetPosition(designArea).Y);
|
||||
designArea.Children.Add(control);
|
||||
};
|
||||
```
|
||||
|
||||
### Пример 3: Календарь с событиями
|
||||
|
||||
```csharp
|
||||
// Событие календаря
|
||||
var calendarEvent = new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.CornflowerBlue),
|
||||
Child = new TextBlock { Text = "Meeting at 10:00" }
|
||||
};
|
||||
|
||||
calendarEvent.MakeDragSource(new CalendarEvent
|
||||
{
|
||||
Id = 1,
|
||||
Title = "Meeting",
|
||||
StartTime = DateTime.Now
|
||||
});
|
||||
|
||||
// Ячейка календаря
|
||||
var timeSlot = new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.White),
|
||||
BorderBrush = new SolidColorBrush(Colors.LightGray)
|
||||
};
|
||||
|
||||
timeSlot.MakeDropTarget(typeof(CalendarEvent));
|
||||
```
|
||||
|
||||
## 🎨 Темы и стилизация
|
||||
|
||||
### Встроенные стили
|
||||
|
||||
Проект включает готовые стили в папке `Themes/`:
|
||||
|
||||
- `DragAdorner.xaml` - стиль для визуального элемента перетаскивания
|
||||
- `DropPreviewAdorner.xaml` - стиль для предпросмотра сброса
|
||||
- `DragDropStyles.xaml` - общие стили для элементов
|
||||
|
||||
### Кастомизация через ресурсы
|
||||
|
||||
```xml
|
||||
<!-- App.xaml или Generic.xaml -->
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ms-appx:///Lattice.UI.DragDrop.WinUI/Themes/Generic.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- Переопределение стилей -->
|
||||
<Style x:Key="CustomDragAdornerStyle" TargetType="dragDrop:DragAdorner">
|
||||
<Setter Property="Background" Value="Red" />
|
||||
<Setter Property="Opacity" Value="0.9" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
```
|
||||
|
||||
### Визуальные состояния
|
||||
|
||||
Элементы поддерживают следующие визуальные состояния:
|
||||
|
||||
- `Normal` - обычное состояние
|
||||
- `Dragging` - элемент перетаскивается
|
||||
- `DragOver` - над элементом перетаскивают объект
|
||||
|
||||
```csharp
|
||||
// Переключение состояний
|
||||
control.SetDragVisualState("Dragging", true); // С анимацией
|
||||
control.SetDragVisualState("Normal", false); // Без анимации
|
||||
```
|
||||
|
||||
## 🔧 Интеграция с Docking System
|
||||
|
||||
Система идеально интегрируется с Lattice Docking:
|
||||
|
||||
```csharp
|
||||
using Lattice.UI.DragDrop.WinUI.Extensions;
|
||||
using Lattice.UI.Docking.WinUI;
|
||||
|
||||
public class DockPane : ContentControl
|
||||
{
|
||||
public DockPane()
|
||||
public async Task<DragInfo?> TryStartDragAsync(Point startPosition, CancellationToken ct)
|
||||
{
|
||||
// Делаем панель перетаскиваемой
|
||||
this.MakeDragSource(new DockPaneDragData
|
||||
// Проверяем, можно ли начать перетаскивание
|
||||
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)
|
||||
{
|
||||
Pane = this,
|
||||
ContentType = Content?.GetType(),
|
||||
Title = Title
|
||||
});
|
||||
|
||||
// Устанавливаем визуальную обратную связь
|
||||
this.ApplyDragStyle();
|
||||
this.EnableDragVisualFeedback();
|
||||
// Удаляем элемент при перемещении
|
||||
await _repository.DeleteAsync(_item.Id, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DockArea : ContentControl
|
||||
{
|
||||
public DockArea()
|
||||
public Task OnDragCancelledAsync(DragInfo dragInfo, CancellationToken ct)
|
||||
{
|
||||
// Область докинга принимает панели
|
||||
this.MakeDropTarget(typeof(DockPaneDragData));
|
||||
|
||||
// Кастомный обработчик
|
||||
this.SetDropHandler(new DockDropHandler());
|
||||
// Очистка ресурсов при отмене
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 Производительность
|
||||
|
||||
### Оптимизации
|
||||
|
||||
1. **Минимальные перерисовки** - обновление только при необходимости
|
||||
2. **Кэширование визуальных элементов** - повторное использование
|
||||
3. **Эффективные алгоритмы поиска** - быстрый поиск целей сброса
|
||||
4. **Асинхронная обработка** - не блокирует UI поток
|
||||
|
||||
### Рекомендации
|
||||
### 3. Создание цели сброса
|
||||
|
||||
```csharp
|
||||
// ✅ Правильно
|
||||
element.MakeDragSource(data);
|
||||
public class ContainerDropTarget : IDropTarget
|
||||
{
|
||||
private readonly ObservableCollection<Item> _items;
|
||||
|
||||
// ❌ Избегать
|
||||
element.PointerPressed += (s, e) => { /* сложная логика */ };
|
||||
element.PointerMoved += (s, e) => { /* частые обновления */ };
|
||||
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
|
||||
[TestClass]
|
||||
public class DragDropTests
|
||||
public class MainViewModel
|
||||
{
|
||||
[TestMethod]
|
||||
public void MakeDragSource_EnablesDragging()
|
||||
private readonly IDragDropService _dragDropService;
|
||||
|
||||
public MainViewModel(IDragDropService dragDropService)
|
||||
{
|
||||
var element = new Border();
|
||||
element.MakeDragSource("test");
|
||||
_dragDropService = dragDropService;
|
||||
|
||||
Assert.IsTrue(element.IsDragSource());
|
||||
// Регистрация цели сброса
|
||||
_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);
|
||||
|
||||
[TestMethod]
|
||||
public void MakeDropTarget_AcceptsCorrectTypes()
|
||||
{
|
||||
var element = new Border();
|
||||
element.MakeDropTarget(typeof(string), typeof(int));
|
||||
|
||||
Assert.IsTrue(element.IsDropTarget());
|
||||
}
|
||||
// Уведомление пользователя
|
||||
_notificationService.ShowError("Ошибка при перетаскивании");
|
||||
}
|
||||
```
|
||||
|
||||
### UI тесты
|
||||
### Кастомизация эффектов
|
||||
|
||||
```csharp
|
||||
[TestClass]
|
||||
public class DragDropUITests
|
||||
// Использование расширений для работы с эффектами
|
||||
if (effects.CanCopy())
|
||||
{
|
||||
[UITestMethod]
|
||||
public async Task DragAndDrop_BetweenElements()
|
||||
{
|
||||
await UITestHelper.Run(async window =>
|
||||
{
|
||||
var source = new Border { Background = new SolidColorBrush(Colors.Blue) };
|
||||
var target = new Border { Background = new SolidColorBrush(Colors.Green) };
|
||||
|
||||
source.MakeDragSource("data");
|
||||
target.MakeDropTarget(typeof(string));
|
||||
|
||||
// Симуляция перетаскивания
|
||||
await SimulateDrag(source, target);
|
||||
|
||||
// Проверка результатов
|
||||
Assert.IsTrue(dropOccurred);
|
||||
});
|
||||
}
|
||||
// Логика для копирования
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 Отладка
|
||||
|
||||
### Включение логов
|
||||
|
||||
```csharp
|
||||
// Включение подробного логирования
|
||||
#if DEBUG
|
||||
DragDropDebugger.EnableLogging = true;
|
||||
DragDropDebugger.LogLevel = LogLevel.Verbose;
|
||||
#endif
|
||||
```
|
||||
|
||||
### Визуальные подсказки
|
||||
|
||||
```csharp
|
||||
// Показать границы целей сброса
|
||||
DebugDropTargets.ShowBounds = true;
|
||||
|
||||
// Показать траекторию перетаскивания
|
||||
DebugDragTrail.Enabled = true;
|
||||
DebugDragTrail.Color = Colors.Red;
|
||||
```
|
||||
|
||||
## 📈 Производительность в production
|
||||
|
||||
### Мониторинг
|
||||
|
||||
```csharp
|
||||
// Сбор метрик
|
||||
var metrics = DragDropPerformanceCollector.Collect();
|
||||
Console.WriteLine($"Drag operations: {metrics.DragCount}");
|
||||
Console.WriteLine($"Average drag time: {metrics.AverageDragTimeMs}ms");
|
||||
Console.WriteLine($"Drop success rate: {metrics.DropSuccessRate:P}");
|
||||
```
|
||||
|
||||
### Оптимизация для больших списков
|
||||
|
||||
```csharp
|
||||
// Виртуализация для списков
|
||||
var virtualizingList = new ListView
|
||||
if (effects.CanMove())
|
||||
{
|
||||
ItemsSource = largeCollection,
|
||||
VirtualizingStackPanel.VirtualizationMode = VirtualizationMode.Recycling
|
||||
};
|
||||
// Логика для перемещения
|
||||
}
|
||||
|
||||
// Оптимизация перетаскивания
|
||||
virtualizingList.MakeDropTarget(typeof(DataItem));
|
||||
virtualizingList.SetDragDropOptimization(true);
|
||||
// Определение эффекта по модификаторам клавиш
|
||||
var effect = DragDropEffectsExtensions.GetEffectFromKeys(
|
||||
controlKey: Keyboard.IsControlDown,
|
||||
shiftKey: Keyboard.IsShiftDown,
|
||||
altKey: Keyboard.IsAltDown
|
||||
);
|
||||
```
|
||||
|
||||
## 🤝 Интеграция с другими компонентами Lattice
|
||||
## 📝 Best Practices
|
||||
|
||||
### Toolbox
|
||||
```csharp
|
||||
toolboxItem.MakeDragSource(new ToolboxItem
|
||||
{
|
||||
Type = typeof(Button),
|
||||
Icon = "🔘"
|
||||
});
|
||||
```
|
||||
1. **Производительность**
|
||||
- Методы `CanAcceptDropAsync` и `OnDragOverAsync` вызываются часто, оптимизируйте их
|
||||
- Избегайте синхронных операций в обработчиках
|
||||
- Используйте кэширование при проверке типов данных
|
||||
|
||||
### Property Grid
|
||||
```csharp
|
||||
propertyItem.MakeDragSource(new PropertyValue
|
||||
{
|
||||
Name = "Background",
|
||||
Value = Colors.Blue
|
||||
});
|
||||
```
|
||||
2. **Безопасность**
|
||||
- Всегда проверяйте тип данных в `CanAcceptDropAsync`
|
||||
- Валидируйте бизнес-правила перед обработкой сброса
|
||||
- Используйте CancellationToken для отмены длительных операций
|
||||
|
||||
### Layout System
|
||||
```csharp
|
||||
layoutPanel.MakeDropTarget(typeof(UIElement));
|
||||
layoutPanel.SetDropPositionHandler((element, position) =>
|
||||
{
|
||||
return CalculateDropZone(position);
|
||||
});
|
||||
```
|
||||
3. **Пользовательский опыт**
|
||||
- Предоставляйте визуальную обратную связь через `DropInfo.ShowVisualFeedback`
|
||||
- Используйте `DropInfo.VisualFeedbackData` для кастомизации отображения
|
||||
- Обрабатывайте отмену операций для очистки временных данных
|
||||
|
||||
## 📚 Дополнительные ресурсы
|
||||
## 🔄 Миграция
|
||||
|
||||
### Документация
|
||||
- [Полная документация API](https://lattice-framework.github.io/ui-dragdrop/api/)
|
||||
- [Примеры использования](https://lattice-framework.github.io/ui-dragdrop/examples/)
|
||||
- [Руководство по стилизации](https://lattice-framework.github.io/ui-dragdrop/styling/)
|
||||
### С версии 1.x на 2.0
|
||||
|
||||
### Видео туториалы
|
||||
- [Быстрый старт](https://youtube.com/playlist?list=...) - 15 минут
|
||||
- [Продвинутые техники](https://youtube.com/playlist?list=...) - 45 минут
|
||||
- [Интеграция с Docking](https://youtube.com/playlist?list=...) - 30 минут
|
||||
1. **Интерфейсы переименованы:**
|
||||
- `CanStartDragAsync` → `TryStartDragAsync`
|
||||
- `DragCompletedAsync` → `OnDragCompletedAsync`
|
||||
- `DragCancelledAsync` → `OnDragCancelledAsync`
|
||||
|
||||
### Сообщество
|
||||
- [GitHub Discussions](https://github.com/lattice-framework/ui-dragdrop/discussions) - вопросы и обсуждения
|
||||
- [Discord](https://discord.gg/lattice) - живое общение
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/lattice-ui-dragdrop) - технические вопросы
|
||||
2. **Классы EventArgs объединены:**
|
||||
- Все события наследуются от `DragEventArgs`
|
||||
- Упрощена иерархия классов событий
|
||||
|
||||
## 🐛 Отчет об ошибках
|
||||
|
||||
Нашли ошибку? [Создайте issue](https://github.com/lattice-framework/ui-dragdrop/issues) с подробным описанием:
|
||||
|
||||
1. Шаги для воспроизведения
|
||||
2. Ожидаемое поведение
|
||||
3. Фактическое поведение
|
||||
4. Скриншоты или видео
|
||||
5. Версии: Windows, WinUI, Lattice
|
||||
|
||||
## 🚀 Roadmap
|
||||
|
||||
### Версия 1.1 (Q2 2024)
|
||||
- [ ] Поддержка touch-жестов
|
||||
- [ ] Анимации с физикой
|
||||
- [ ] Расширенная визуализация
|
||||
|
||||
### Версия 1.2 (Q3 2024)
|
||||
- [ ] Интеграция с Windows Shell
|
||||
- [ ] Поддержка виртуальных данных
|
||||
- [ ] Улучшенная доступность
|
||||
|
||||
### Версия 2.0 (Q4 2024)
|
||||
- [ ] Кроссплатформенная поддержка (Uno Platform)
|
||||
- [ ] WebAssembly поддержка
|
||||
- [ ] Расширенный набор контролов
|
||||
3. **Удалены устаревшие компоненты:**
|
||||
- `AsyncDragDropUtilities` удален
|
||||
- `ServiceCollectionExtensions` удален
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
MIT License. Подробности в файле [LICENSE](LICENSE).
|
||||
Библиотека распространяется под лицензией MIT. Подробности см. в файле LICENSE.
|
||||
|
||||
## 👥 Авторы
|
||||
## 🤝 Вклад в разработку
|
||||
|
||||
- **Команда Lattice Framework** - [@lattice-framework](https://github.com/lattice-framework)
|
||||
- **Главный разработчик** - [Ваше имя](https://github.com/yourusername)
|
||||
Мы приветствуем вклад в развитие библиотеки. Перед отправкой pull request ознакомьтесь с руководством по контрибьютингу.
|
||||
|
||||
## 🙏 Благодарности
|
||||
## 🐛 Отчеты об ошибках
|
||||
|
||||
Спасибо сообществу WinUI и всем контрибьюторам, которые помогают улучшать проект!
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<p>
|
||||
<strong>Lattice.UI.DragDrop.WinUI</strong> - часть <a href="https://github.com/lattice-framework">Lattice UI Framework</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://github.com/lattice-framework/ui-dragdrop">GitHub</a> •
|
||||
<a href="https://lattice-framework.github.io">Документация</a> •
|
||||
<a href="https://discord.gg/lattice">Discord</a> •
|
||||
<a href="https://twitter.com/latticefw">Twitter</a>
|
||||
</p>
|
||||
</div>
|
||||
Для сообщения об ошибках используйте Issues на GitHub. Пожалуйста, указывайте:
|
||||
- Версию библиотеки
|
||||
- Шаги для воспроизведения
|
||||
- Ожидаемое и фактическое поведение
|
||||
- Пример кода для демонстрации проблемы
|
||||
Reference in New Issue
Block a user