доработана winUI реализация
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.Core.Geometry;
|
||||
using Lattice.UI.DragDrop.WinUI.Behaviors;
|
||||
using Lattice.UI.DragDrop.WinUI.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
@@ -9,41 +10,87 @@ namespace Lattice.UI.DragDrop.WinUI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Центральный менеджер для управления операциями drag-and-drop в WinUI приложении.
|
||||
/// Координирует работу источников и целей перетаскивания, управляет визуальной обратной связью
|
||||
/// и обеспечивает согласованное взаимодействие всех компонентов системы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот класс реализует шаблон Singleton и предоставляет единую точку для
|
||||
/// настройки и управления всеми операциями перетаскивания в приложении.
|
||||
/// <see cref="WinUIDragDropManager"/> реализует шаблон Singleton и служит единой точкой
|
||||
/// входа для настройки и управления операциями перетаскивания в WinUI-приложении.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Менеджер отвечает за:
|
||||
/// - Инициализацию системы перетаскивания
|
||||
/// - Регистрацию и отслеживание источников и целей перетаскивания
|
||||
/// - Создание и управление визуальной обратной связью
|
||||
/// - Координацию между поведением элементов и базовым сервисом перетаскивания
|
||||
/// Основные функции менеджера:
|
||||
/// <list type="bullet">
|
||||
/// <item>Инициализация системы перетаскивания для конкретного окна</item>
|
||||
/// <item>Регистрация и отслеживание источников и целей перетаскивания</item>
|
||||
/// <item>Управление жизненным циклом операций перетаскивания</item>
|
||||
/// <item>Обеспечение визуальной обратной связи через <see cref="WinUIDragDropHost"/></item>
|
||||
/// <item>Координация взаимодействия между <see cref="WinUIDragSourceBehavior"/> и <see cref="WinUIDropTargetBehavior"/></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Для использования необходимо вызвать <see cref="Initialize"/> при запуске приложения
|
||||
/// и использовать attached properties или методы расширения для настройки элементов.
|
||||
/// Для использования менеджера необходимо:
|
||||
/// <list type="number">
|
||||
/// <item>Вызвать <see cref="Initialize"/> при создании главного окна приложения</item>
|
||||
/// <item>Настроить элементы как источники или цели через методы <see cref="MakeDragSource"/> и <see cref="MakeDropTarget"/></item>
|
||||
/// <item>Использовать attached properties для декларативной настройки в XAML</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // Инициализация в коде
|
||||
/// public partial class MainWindow : Window
|
||||
/// {
|
||||
/// private WinUIDragDropManager _manager;
|
||||
///
|
||||
/// public MainWindow()
|
||||
/// {
|
||||
/// InitializeComponent();
|
||||
/// _manager = WinUIDragDropManager.Instance;
|
||||
/// _manager.Initialize(this);
|
||||
///
|
||||
/// // Настройка элементов
|
||||
/// _manager.MakeDragSource(myElement, myData);
|
||||
/// _manager.MakeDropTarget(myDropArea);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Или через attached properties в XAML
|
||||
/// <Border x:Name="DragElement"
|
||||
/// local:DragDropProperties.IsDragSource="True"
|
||||
/// local:DragDropProperties.DragData="{Binding MyData}" />
|
||||
/// <Border x:Name="DropArea"
|
||||
/// local:DragDropProperties.IsDropTarget="True" />
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public sealed class WinUIDragDropManager : IDisposable
|
||||
{
|
||||
#region Singleton
|
||||
#region Singleton Implementation
|
||||
|
||||
private static WinUIDragDropManager? _instance;
|
||||
private static readonly object _lock = new();
|
||||
private static readonly object _lockObject = new();
|
||||
|
||||
/// <summary>
|
||||
/// Получает единственный экземпляр менеджера.
|
||||
/// Получает единственный экземпляр <see cref="WinUIDragDropManager"/>.
|
||||
/// Реализует шаблон Singleton с ленивой инициализацией и потокобезопасностью.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Единственный экземпляр менеджера перетаскивания для всего приложения.
|
||||
/// Если экземпляр еще не создан, он будет инициализирован при первом обращении.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Использование Singleton гарантирует, что во всем приложении существует только один
|
||||
/// экземпляр менеджера, что обеспечивает согласованное управление всеми операциями
|
||||
/// перетаскивания и предотвращает конфликты между разными компонентами системы.
|
||||
/// </remarks>
|
||||
public static WinUIDragDropManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
lock (_lockObject)
|
||||
{
|
||||
_instance ??= new WinUIDragDropManager();
|
||||
}
|
||||
@@ -54,37 +101,107 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
#region Поля
|
||||
#region Fields
|
||||
|
||||
private readonly DragDropService _dragDropService;
|
||||
private readonly IDragDropService _dragDropService;
|
||||
private readonly WinUIDragDropHost _host;
|
||||
private readonly Dictionary<FrameworkElement, Behaviors.WinUIDragSourceBehavior> _dragSources = new();
|
||||
private readonly Dictionary<FrameworkElement, Behaviors.WinUIDropTargetBehavior> _dropTargets = new();
|
||||
private readonly Dictionary<FrameworkElement, WinUIDragSourceBehavior> _dragSources = new();
|
||||
private readonly Dictionary<FrameworkElement, WinUIDropTargetBehavior> _dropTargets = new();
|
||||
private DragAdorner? _currentDragVisual;
|
||||
private bool _disposed;
|
||||
private bool _initialized;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Свойства
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Получает основной сервис перетаскивания.
|
||||
/// Получает сервис перетаскивания, используемый менеджером для координации операций.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDragDropService"/>, через который менеджер взаимодействует
|
||||
/// с ядром системы перетаскивания.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Этот сервис предоставляет низкоуровневый API для управления операциями перетаскивания
|
||||
/// и может использоваться для расширенной настройки системы.
|
||||
/// </remarks>
|
||||
public IDragDropService DragDropService => _dragDropService;
|
||||
|
||||
/// <summary>
|
||||
/// Получает хост для управления визуальными элементами перетаскивания.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="WinUIDragDropHost"/>, отвечающий за отображение и позиционирование
|
||||
/// визуальной обратной связи во время операций перетаскивания.
|
||||
/// </value>
|
||||
public WinUIDragDropHost Host => _host;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает смещение визуального элемента перетаскивания относительно курсора.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Точка, определяющая смещение по осям X и Y. Значение по умолчанию: (-20, -20).
|
||||
/// Отрицательные значения поднимают визуальный элемент вверх и влево относительно курсора.
|
||||
/// Точка, определяющая смещение по осям X и Y в пикселях.
|
||||
/// Значение по умолчанию: (-20, -20).
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Отрицательные значения смещают визуальный элемент вверх и влево относительно курсора,
|
||||
/// что является стандартным поведением в большинстве систем drag-and-drop.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Настройка смещения позволяет:
|
||||
/// <list type="bullet">
|
||||
/// <item>Предотвратить перекрытие курсора визуальным элементом</item>
|
||||
/// <item>Обеспечить лучшую видимость области под курсором</item>
|
||||
/// <item>Создать более естественное визуальное восприятие</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // Настройка смещения через фабрику
|
||||
/// var manager = WinUIDragDropFactory.CreateManager(window, m =>
|
||||
/// {
|
||||
/// m.DragVisualOffset = new Point(-15, -15); // Более близко к курсору
|
||||
/// });
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public Point DragVisualOffset { get; set; } = new Point(-20, -20);
|
||||
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее, инициализирован ли менеджер.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если метод <see cref="Initialize"/> был успешно вызван;
|
||||
/// в противном случае — false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Проверка этого свойства позволяет избежать повторной инициализации менеджера
|
||||
/// и гарантирует, что система перетаскивания готова к использованию.
|
||||
/// </remarks>
|
||||
public bool IsInitialized => _initialized;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Конструктор
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="WinUIDragDropManager"/>.
|
||||
/// Конструктор является приватным в соответствии с шаблоном Singleton.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Внутренний конструктор создает:
|
||||
/// <list type="bullet">
|
||||
/// <item>Экземпляр <see cref="DragDropService"/> для управления операциями перетаскивания</item>
|
||||
/// <item>Экземпляр <see cref="WinUIDragDropHost"/> для визуальной обратной связи</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Для получения экземпляра менеджера используйте свойство <see cref="Instance"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private WinUIDragDropManager()
|
||||
{
|
||||
_dragDropService = new DragDropService();
|
||||
@@ -93,71 +210,196 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
#region Публичные методы
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует систему перетаскивания для указанного окна.
|
||||
/// Инициализирует систему перетаскивания для указанного окна WinUI.
|
||||
/// Этот метод должен быть вызван один раз при запуске приложения.
|
||||
/// </summary>
|
||||
/// <param name="window">Основное окно приложения, в котором будет работать перетаскивание.</param>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Выбрасывается, если менеджер был удален.
|
||||
/// <param name="window">
|
||||
/// Главное окно приложения, для которого настраивается система перетаскивания.
|
||||
/// Не может быть null.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="window"/> равен null.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если менеджер уже инициализирован или был удален.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть вызван один раз при запуске приложения, обычно в методе
|
||||
/// <see cref="Application.OnLaunched"/>.
|
||||
/// <para>
|
||||
/// Этот метод выполняет следующие действия:
|
||||
/// <list type="bullet">
|
||||
/// <item>Настраивает хост визуальных элементов для работы с указанным окном</item>
|
||||
/// <item>Подписывается на события сервиса перетаскивания для управления визуальной обратной связью</item>
|
||||
/// <item>Помечает менеджер как инициализированный</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Метод должен быть вызван до использования любых других методов менеджера.
|
||||
/// Рекомендуется вызывать его в конструкторе главного окна приложения.
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public MainWindow()
|
||||
/// {
|
||||
/// InitializeComponent();
|
||||
/// WinUIDragDropManager.Instance.Initialize(this);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public void Initialize(Window window)
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(nameof(WinUIDragDropManager));
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(WinUIDragDropManager));
|
||||
|
||||
if (_initialized)
|
||||
throw new InvalidOperationException("Менеджер уже инициализирован.");
|
||||
|
||||
if (window == null)
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
|
||||
// Инициализируем хост для работы с окном
|
||||
_host.Initialize(window);
|
||||
|
||||
// Подписываемся на события
|
||||
// Подписываемся на события сервиса перетаскивания
|
||||
_dragDropService.DragStarted += OnDragStarted;
|
||||
_dragDropService.DragUpdated += OnDragUpdated;
|
||||
_dragDropService.DragCompleted += OnDragCompleted;
|
||||
_dragDropService.DragCancelled += OnDragCancelled;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Делает указанный элемент источником перетаскивания.
|
||||
/// Настраивает указанный элемент как источник перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент, который станет источником перетаскивания.</param>
|
||||
/// <param name="dragData">Данные, которые будут перетаскиваться. Если не указано, используются
|
||||
/// DataContext или Tag элемента.</param>
|
||||
/// <param name="element">
|
||||
/// Элемент <see cref="FrameworkElement"/ который должен стать источником перетаскивания.
|
||||
/// Не может быть null.
|
||||
/// </param>
|
||||
/// <param name="dragData">
|
||||
/// Данные, которые будут перетаскиваться. Может быть null.
|
||||
/// Если не указано, используются <see cref="FrameworkElement.DataContext"/> или
|
||||
/// <see cref="FrameworkElement.Tag"/> элемента.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="element"/> равен null.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если менеджер не инициализирован или был удален.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// После вызова этого метода элемент приобретает следующие возможности:
|
||||
/// <list type="bullet">
|
||||
/// <item>Реагирует на жесты перетаскивания (удержание и перемещение указателя)</item>
|
||||
/// <item>Предоставляет указанные данные для перетаскивания</item>
|
||||
/// <item>Интегрируется с системой визуальной обратной связи</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Если элемент уже зарегистрирован как источник перетаскивания, метод не выполняет действий.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Для отмены регистрации используйте метод <see cref="RemoveDragSource"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void MakeDragSource(FrameworkElement element, object? dragData = null)
|
||||
{
|
||||
if (_disposed || _dragSources.ContainsKey(element)) return;
|
||||
ValidateManagerState();
|
||||
|
||||
var behavior = new Behaviors.WinUIDragSourceBehavior(_dragDropService, _host);
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
// Если элемент уже зарегистрирован, ничего не делаем
|
||||
if (_dragSources.ContainsKey(element))
|
||||
return;
|
||||
|
||||
// Создаем и настраиваем поведение
|
||||
var behavior = new WinUIDragSourceBehavior(_dragDropService, _host);
|
||||
behavior.Attach(element, dragData);
|
||||
_dragSources[element] = behavior;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Делает указанный элемент целью сброса.
|
||||
/// Настраивает указанный элемент как цель сброса.
|
||||
/// </summary>
|
||||
/// <param name="element">Элемент, который станет целью сброса.</param>
|
||||
/// <param name="element">
|
||||
/// Элемент <see cref="FrameworkElement"/>, который должен стать целью сброса.
|
||||
/// Не может быть null.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="element"/> равен null.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если менеджер не инициализирован или был удален.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// После вызова этого метода элемент приобретает следующие возможности:
|
||||
/// <list type="bullet">
|
||||
/// <item>Принимает данные, сбрасываемые пользователем</item>
|
||||
/// <item>Предоставляет визуальную обратную связь при наведении</item>
|
||||
/// <item>Автоматически обновляет свои границы при изменении размера или позиции</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// По умолчанию цель принимает данные любого типа. Для настройки фильтрации типов
|
||||
/// используйте методы <see cref="WinUIDropTargetBehavior.AcceptTypes"/> и
|
||||
/// <see cref="WinUIDropTargetBehavior.AcceptFormats"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Если элемент уже зарегистрирован как цель сброса, метод не выполняет действий.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Для отмены регистрации используйте метод <see cref="RemoveDropTarget"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void MakeDropTarget(FrameworkElement element)
|
||||
{
|
||||
if (_disposed || _dropTargets.ContainsKey(element)) return;
|
||||
ValidateManagerState();
|
||||
|
||||
var behavior = new Behaviors.WinUIDropTargetBehavior(_dragDropService, _host);
|
||||
if (element == null)
|
||||
throw new ArgumentNullException(nameof(element));
|
||||
|
||||
// Если элемент уже зарегистрирован, ничего не делаем
|
||||
if (_dropTargets.ContainsKey(element))
|
||||
return;
|
||||
|
||||
// Создаем и настраиваем поведение
|
||||
var behavior = new WinUIDropTargetBehavior(_dragDropService, _host);
|
||||
behavior.Attach(element);
|
||||
_dropTargets[element] = behavior;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет возможность перетаскивания.
|
||||
/// Удаляет возможность перетаскивания у указанного элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">
|
||||
/// Элемент, у которого нужно отключить возможность перетаскивания.
|
||||
/// Если элемент не зарегистрирован как источник перетаскивания, метод не выполняет действий.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод выполняет следующие действия:
|
||||
/// <list type="bullet">
|
||||
/// <item>Открепляет поведение перетаскивания от элемента</item>
|
||||
/// <item>Отписывается от всех событий элемента</item>
|
||||
/// <item>Удаляет элемент из внутреннего словаря источников</item>
|
||||
/// <item>Освобождает ресурсы, связанные с поведением</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Метод безопасен для вызова даже если элемент не был зарегистрирован как источник.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void RemoveDragSource(FrameworkElement element)
|
||||
{
|
||||
if (element == null || _disposed || !_dragSources.ContainsKey(element))
|
||||
return;
|
||||
|
||||
if (_dragSources.Remove(element, out var behavior))
|
||||
{
|
||||
behavior.Detach();
|
||||
@@ -165,10 +407,31 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет возможность сброса.
|
||||
/// Удаляет возможность сброса у указанного элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">
|
||||
/// Элемент, у которого нужно отключить возможность сброса.
|
||||
/// Если элемент не зарегистрирован как цель сброса, метод не выполняет действий.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод выполняет следующие действия:
|
||||
/// <list type="bullet">
|
||||
/// <item>Открепляет поведение цели сброса от элемента</item>
|
||||
/// <item>Восстанавливает свойство <see cref="UIElement.AllowDrop"/> = false</item>
|
||||
/// <item>Удаляет элемент из внутреннего словаря целей</item>
|
||||
/// <item>Освобождает ресурсы, связанные с поведением</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Метод безопасен для вызова даже если элемент не был зарегистрирован как цель.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void RemoveDropTarget(FrameworkElement element)
|
||||
{
|
||||
if (element == null || _disposed || !_dropTargets.ContainsKey(element))
|
||||
return;
|
||||
|
||||
if (_dropTargets.Remove(element, out var behavior))
|
||||
{
|
||||
behavior.Detach();
|
||||
@@ -176,16 +439,35 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Очищает все регистрации.
|
||||
/// Очищает все регистрации источников и целей перетаскивания.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод полезен в следующих сценариях:
|
||||
/// <list type="bullet">
|
||||
/// <item>При перезагрузке содержимого интерфейса</item>
|
||||
/// <item>При смене контекста данных</item>
|
||||
/// <item>При освобождении ресурсов перед удалением менеджера</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// После вызова этого метода все элементы теряют возможность участвовать в операциях
|
||||
/// перетаскивания. Для восстановления функциональности необходимо повторно
|
||||
/// зарегистрировать элементы через <see cref="MakeDragSource"/> и <see cref="MakeDropTarget"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Clear()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
// Открепляем все источники
|
||||
foreach (var behavior in _dragSources.Values)
|
||||
{
|
||||
behavior.Detach();
|
||||
}
|
||||
_dragSources.Clear();
|
||||
|
||||
// Открепляем все цели
|
||||
foreach (var behavior in _dropTargets.Values)
|
||||
{
|
||||
behavior.Detach();
|
||||
@@ -195,27 +477,37 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
#region Обработчики событий
|
||||
#region Event Handlers
|
||||
|
||||
private void OnDragStarted(object? sender, DragStartedEventArgs e)
|
||||
/// <summary>
|
||||
/// Обрабатывает событие начала перетаскивания.
|
||||
/// Создает и отображает визуальный элемент для обратной связи.
|
||||
/// </summary>
|
||||
private void OnDragStarted(object? sender, Core.DragDrop.Services.DragStartedEventArgs e)
|
||||
{
|
||||
// Создаем визуальное представление
|
||||
// Создаем визуальное представление перетаскивания
|
||||
_currentDragVisual = new DragAdorner
|
||||
{
|
||||
DragData = e.DragInfo.Data,
|
||||
Opacity = 0.8
|
||||
};
|
||||
|
||||
// Рассчитываем позицию с учетом смещения
|
||||
var position = new Point(
|
||||
e.Position.X + DragVisualOffset.X,
|
||||
e.Position.Y + DragVisualOffset.Y
|
||||
);
|
||||
|
||||
// Обновляем позицию и показываем элемент
|
||||
_currentDragVisual.UpdatePosition(position);
|
||||
_host.ShowDragVisual(_currentDragVisual, position);
|
||||
}
|
||||
|
||||
private void OnDragUpdated(object? sender, DragUpdatedEventArgs e)
|
||||
/// <summary>
|
||||
/// Обрабатывает событие обновления позиции перетаскивания.
|
||||
/// Обновляет позицию визуального элемента для следования за курсором.
|
||||
/// </summary>
|
||||
private void OnDragUpdated(object? sender, Core.DragDrop.Services.DragUpdatedEventArgs e)
|
||||
{
|
||||
if (_currentDragVisual != null)
|
||||
{
|
||||
@@ -228,16 +520,27 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDragCompleted(object? sender, DragCompletedEventArgs e)
|
||||
/// <summary>
|
||||
/// Обрабатывает событие завершения перетаскивания.
|
||||
/// Очищает визуальные элементы и восстанавливает состояние.
|
||||
/// </summary>
|
||||
private void OnDragCompleted(object? sender, Core.DragDrop.Services.DragCompletedEventArgs e)
|
||||
{
|
||||
CleanupDragVisual();
|
||||
}
|
||||
|
||||
private void OnDragCancelled(object? sender, DragCancelledEventArgs e)
|
||||
/// <summary>
|
||||
/// Обрабатывает событие отмены перетаскивания.
|
||||
/// Очищает визуальные элементы и восстанавливает состояние.
|
||||
/// </summary>
|
||||
private void OnDragCancelled(object? sender, Core.DragDrop.Services.DragCancelledEventArgs e)
|
||||
{
|
||||
CleanupDragVisual();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Освобождает ресурсы визуального элемента перетаскивания.
|
||||
/// </summary>
|
||||
private void CleanupDragVisual()
|
||||
{
|
||||
if (_currentDragVisual != null)
|
||||
@@ -249,24 +552,72 @@ public sealed class WinUIDragDropManager : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
#region Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет состояние менеджера перед выполнением операций.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// Выбрасывается, если менеджер был удален.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если менеджер не инициализирован.
|
||||
/// </exception>
|
||||
private void ValidateManagerState()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(WinUIDragDropManager));
|
||||
|
||||
if (!_initialized)
|
||||
throw new InvalidOperationException(
|
||||
"Менеджер не инициализирован. Вызовите метод Initialize перед использованием.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Освобождает все ресурсы, используемые <see cref="WinUIDragDropManager"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод выполняет следующие действия:
|
||||
/// <list type="bullet">
|
||||
/// <item>Отписывается от всех событий сервиса перетаскивания</item>
|
||||
/// <item>Очищает все зарегистрированные источники и цели</item>
|
||||
/// <item>Освобождает ресурсы хоста визуальных элементов</item>
|
||||
/// <item>Освобождает ресурсы сервиса перетаскивания</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// После вызова этого метода менеджер перестает быть пригодным для использования.
|
||||
/// Попытка использовать методы менеджера после удаления приведет к исключению
|
||||
/// <see cref="ObjectDisposedException"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Метод безопасен для многократного вызова.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
Clear();
|
||||
|
||||
// Отписываемся от событий
|
||||
_dragDropService.DragStarted -= OnDragStarted;
|
||||
_dragDropService.DragUpdated -= OnDragUpdated;
|
||||
_dragDropService.DragCompleted -= OnDragCompleted;
|
||||
_dragDropService.DragCancelled -= OnDragCancelled;
|
||||
|
||||
// Очищаем все регистрации
|
||||
Clear();
|
||||
|
||||
// Освобождаем ресурсы
|
||||
_dragDropService.Dispose();
|
||||
_host.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
_initialized = false;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user