625 lines
28 KiB
C#
625 lines
28 KiB
C#
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;
|
||
using System.Collections.Generic;
|
||
|
||
namespace Lattice.UI.DragDrop.WinUI.Services;
|
||
|
||
/// <summary>
|
||
/// Центральный менеджер для управления операциями drag-and-drop в WinUI приложении.
|
||
/// Координирует работу источников и целей перетаскивания, управляет визуальной обратной связью
|
||
/// и обеспечивает согласованное взаимодействие всех компонентов системы.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// <para>
|
||
/// <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>
|
||
/// Для использования менеджера необходимо:
|
||
/// <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 Implementation
|
||
|
||
private static WinUIDragDropManager? _instance;
|
||
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 (_lockObject)
|
||
{
|
||
_instance ??= new WinUIDragDropManager();
|
||
}
|
||
}
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Fields
|
||
|
||
private readonly IDragDropService _dragDropService;
|
||
private readonly WinUIDragDropHost _host;
|
||
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 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).
|
||
/// </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 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();
|
||
_host = new WinUIDragDropHost();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Public Methods
|
||
|
||
/// <summary>
|
||
/// Инициализирует систему перетаскивания для указанного окна WinUI.
|
||
/// Этот метод должен быть вызван один раз при запуске приложения.
|
||
/// </summary>
|
||
/// <param name="window">
|
||
/// Главное окно приложения, для которого настраивается система перетаскивания.
|
||
/// Не может быть null.
|
||
/// </param>
|
||
/// <exception cref="ArgumentNullException">
|
||
/// Выбрасывается, если <paramref name="window"/> равен null.
|
||
/// </exception>
|
||
/// <exception cref="InvalidOperationException">
|
||
/// Выбрасывается, если менеджер уже инициализирован или был удален.
|
||
/// </exception>
|
||
/// <remarks>
|
||
/// <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 (_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">
|
||
/// Элемент <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)
|
||
{
|
||
ValidateManagerState();
|
||
|
||
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">
|
||
/// Элемент <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)
|
||
{
|
||
ValidateManagerState();
|
||
|
||
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();
|
||
}
|
||
}
|
||
|
||
/// <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();
|
||
}
|
||
}
|
||
|
||
/// <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();
|
||
}
|
||
_dropTargets.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Event Handlers
|
||
|
||
/// <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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обрабатывает событие обновления позиции перетаскивания.
|
||
/// Обновляет позицию визуального элемента для следования за курсором.
|
||
/// </summary>
|
||
private void OnDragUpdated(object? sender, Core.DragDrop.Services.DragUpdatedEventArgs e)
|
||
{
|
||
if (_currentDragVisual != null)
|
||
{
|
||
var position = new Point(
|
||
e.Position.X + DragVisualOffset.X,
|
||
e.Position.Y + DragVisualOffset.Y
|
||
);
|
||
|
||
_currentDragVisual.UpdatePosition(position);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обрабатывает событие завершения перетаскивания.
|
||
/// Очищает визуальные элементы и восстанавливает состояние.
|
||
/// </summary>
|
||
private void OnDragCompleted(object? sender, Core.DragDrop.Services.DragCompletedEventArgs e)
|
||
{
|
||
CleanupDragVisual();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обрабатывает событие отмены перетаскивания.
|
||
/// Очищает визуальные элементы и восстанавливает состояние.
|
||
/// </summary>
|
||
private void OnDragCancelled(object? sender, Core.DragDrop.Services.DragCancelledEventArgs e)
|
||
{
|
||
CleanupDragVisual();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Освобождает ресурсы визуального элемента перетаскивания.
|
||
/// </summary>
|
||
private void CleanupDragVisual()
|
||
{
|
||
if (_currentDragVisual != null)
|
||
{
|
||
_currentDragVisual.Hide();
|
||
_currentDragVisual = null;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#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;
|
||
|
||
// Отписываемся от событий
|
||
_dragDropService.DragStarted -= OnDragStarted;
|
||
_dragDropService.DragUpdated -= OnDragUpdated;
|
||
_dragDropService.DragCompleted -= OnDragCompleted;
|
||
_dragDropService.DragCancelled -= OnDragCancelled;
|
||
|
||
// Очищаем все регистрации
|
||
Clear();
|
||
|
||
// Освобождаем ресурсы
|
||
_dragDropService.Dispose();
|
||
_host.Dispose();
|
||
|
||
_disposed = true;
|
||
_initialized = false;
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
|
||
#endregion
|
||
} |