Files
Lattice/Lattice.UI.DragDrop.WinUI/Services/DragDropConfigurationService.cs
2026-01-18 16:33:35 +03:00

259 lines
8.1 KiB
C#
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.
using Lattice.UI.DragDrop.WinUI.Controls;
using Lattice.UI.DragDrop.WinUI.Extensions;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
namespace Lattice.UI.DragDrop.WinUI.Services;
/// <summary>
/// Сервис для настройки перетаскивания с поддержкой различных сценариев.
/// </summary>
public class DragDropConfigurationService
{
private readonly Dictionary<UIElement, Configuration> _configurations = new();
private readonly DragDropOverlay _overlay;
/// <summary>
/// Инициализирует новый экземпляр класса <see cref="DragDropConfigurationService"/>.
/// </summary>
public DragDropConfigurationService()
{
_overlay = new DragDropOverlay();
}
/// <summary>
/// Настройка элемента как источника перетаскивания.
/// </summary>
public void ConfigureAsDragSource(UIElement element, DragSourceConfiguration config)
{
element.MakeDragSource(config.Data);
if (config.AllowedEffects.HasValue)
{
element.SetAllowedEffects(config.AllowedEffects.Value);
}
if (config.VisualOffset.HasValue)
{
element.SetDragVisualOffset(config.VisualOffset.Value.X, config.VisualOffset.Value.Y);
}
_configurations[element] = new Configuration { DragSourceConfig = config };
}
/// <summary>
/// Настройка элемента как цели сброса.
/// </summary>
public void ConfigureAsDropTarget(UIElement element, DropTargetConfiguration config)
{
element.MakeDropTarget(
config.AcceptedTypes,
config.Handler,
config.ShowVisualFeedback,
config.FeedbackStyle);
if (!_configurations.ContainsKey(element))
{
_configurations[element] = new Configuration();
}
_configurations[element].DropTargetConfig = config;
}
/// <summary>
/// Настройка элемента для переупорядочивания в контейнере.
/// </summary>
public void ConfigureForReorder(UIElement element, Panel container, ReorderConfiguration config)
{
ConfigureAsDragSource(element, new DragSourceConfiguration
{
Data = element,
AllowedEffects = Core.DragDrop.Enums.DragDropEffects.Move,
VisualOffset = new Windows.Foundation.Point(-20, -20)
});
ConfigureAsDropTarget(container, new DropTargetConfiguration
{
AcceptedTypes = new[] { typeof(UIElement) },
ShowVisualFeedback = config.ShowVisualFeedback,
FeedbackStyle = config.FeedbackStyle
});
// Настраиваем логику переупорядочивания
container.Drop += (sender, e) => HandleReorderDrop(sender as Panel, element, e);
}
/// <summary>
/// Подключает оверлей к указанному контейнеру.
/// </summary>
public void AttachOverlayTo(Panel container)
{
if (container.Children.Contains(_overlay))
return;
container.Children.Add(_overlay);
}
/// <summary>
/// Отключает все настройки перетаскивания для элемента.
/// </summary>
public void DisableDragDrop(UIElement element)
{
element.RemoveDragSource();
element.RemoveDropTarget();
_configurations.Remove(element);
}
/// <summary>
/// Очищает все настройки.
/// </summary>
public void Clear()
{
foreach (var element in _configurations.Keys)
{
element.RemoveDragSource();
element.RemoveDropTarget();
}
_configurations.Clear();
}
private void HandleReorderDrop(Panel? container, UIElement draggedElement, Microsoft.UI.Xaml.DragEventArgs e)
{
if (container == null) return;
var position = e.GetPosition(container);
int insertIndex = CalculateInsertIndex(container, position);
if (insertIndex >= 0 && insertIndex < container.Children.Count)
{
container.Children.Remove(draggedElement);
container.Children.Insert(insertIndex, draggedElement);
}
}
private int CalculateInsertIndex(Panel container, Windows.Foundation.Point position)
{
for (int i = 0; i < container.Children.Count; i++)
{
var child = container.Children[i];
if (child is FrameworkElement element)
{
var childBounds = new Windows.Foundation.Rect(
Canvas.GetLeft(element),
Canvas.GetTop(element),
element.ActualWidth,
element.ActualHeight);
if (position.Y < childBounds.Y + childBounds.Height / 2)
{
return i;
}
}
}
return container.Children.Count;
}
private class Configuration
{
public DragSourceConfiguration? DragSourceConfig { get; set; }
public DropTargetConfiguration? DropTargetConfig { get; set; }
}
}
/// <summary>
/// Конфигурация источника перетаскивания.
/// </summary>
public class DragSourceConfiguration
{
/// <summary>
/// Данные для перетаскивания.
/// </summary>
public required object Data { get; set; }
/// <summary>
/// Разрешенные эффекты.
/// </summary>
public Core.DragDrop.Enums.DragDropEffects? AllowedEffects { get; set; }
/// <summary>
/// Смещение визуального элемента.
/// </summary>
public Windows.Foundation.Point? VisualOffset { get; set; }
/// <summary>
/// Пользовательский обработчик.
/// </summary>
public Action<UIElement>? OnDragStarted { get; set; }
/// <summary>
/// Пользовательский обработчик завершения.
/// </summary>
public Action<UIElement, Core.DragDrop.Enums.DragDropEffects>? OnDragCompleted { get; set; }
}
/// <summary>
/// Конфигурация цели сброса.
/// </summary>
public class DropTargetConfiguration
{
/// <summary>
/// Принимаемые типы данных.
/// </summary>
public Type[]? AcceptedTypes { get; set; }
/// <summary>
/// Обработчик сброса.
/// </summary>
public Core.DragDrop.Abstractions.IDropTarget? Handler { get; set; }
/// <summary>
/// Показывать визуальную обратную связь.
/// </summary>
public bool ShowVisualFeedback { get; set; } = true;
/// <summary>
/// Стиль визуальной обратной связи.
/// </summary>
public Style? FeedbackStyle { get; set; }
/// <summary>
/// Пользовательский обработчик валидации.
/// </summary>
public Func<object, bool>? CustomValidation { get; set; }
/// <summary>
/// Пользовательский обработчик сброса.
/// </summary>
public Action<object>? OnDrop { get; set; }
}
/// <summary>
/// Конфигурация переупорядочивания.
/// </summary>
public class ReorderConfiguration
{
/// <summary>
/// Показывать визуальную обратную связь.
/// </summary>
public bool ShowVisualFeedback { get; set; } = true;
/// <summary>
/// Стиль визуальной обратной связи.
/// </summary>
public Style? FeedbackStyle { get; set; }
/// <summary>
/// Включать анимацию при переупорядочивании.
/// </summary>
public bool EnableAnimation { get; set; } = true;
/// <summary>
/// Порог для начала перетаскивания (в пикселях).
/// </summary>
public double DragThreshold { get; set; } = 5.0;
}