DragAndDrop core
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user