using Lattice.Core.Geometry; using Lattice.UI.DragDrop.Abstractions; using Lattice.UI.DragDrop.WinUI.Controls; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; namespace Lattice.UI.DragDrop.WinUI.Services; /// /// Хост для управления визуальными элементами перетаскивания в окне WinUI. /// /// /// /// Этот класс отвечает за отображение и управление визуальными элементами /// во время операций перетаскивания, включая: /// - Drag-визуализацию (элемент, следующий за курсором) /// - Drop-превью (подсветка областей сброса) /// /// /// Хост создает оверлейный слой поверх всего содержимого окна для корректного /// отображения визуальных элементов поверх других UI-компонентов. /// /// public sealed class WinUIDragDropHost : IDragDropHost, IDisposable { private DragDropOverlay? _overlay; private Window? _window; private bool _disposed; /// /// Инициализирует хост для работы с указанным окном. /// /// Окно, в котором будет работать перетаскивание. /// /// Выбрасывается, если равен null. /// /// /// Выбрасывается, если хост уже был удален. /// /// /// /// Этот метод создает оверлейный слой и добавляет его в визуальное дерево окна. /// Если содержимое окна не является , создается контейнер . /// /// /// Метод должен быть вызван один раз перед использованием других методов хоста. /// /// public void Initialize(Window window) { if (_disposed) throw new ObjectDisposedException(nameof(WinUIDragDropHost)); _window = window ?? throw new ArgumentNullException(nameof(window)); // Создаем оверлей _overlay = new DragDropOverlay(); // Добавляем оверлей в окно if (_window.Content is Panel panel) { panel.Children.Add(_overlay); } else { // Если контент не Panel, создаем Grid var grid = new Grid(); grid.Children.Add(_window.Content as UIElement ?? new Grid()); grid.Children.Add(_overlay); _window.Content = grid; } } /// /// Отображает визуальное представление перетаскиваемого элемента. /// /// Визуальный элемент для отображения. /// Позиция отображения в координатах экрана. /// /// Визуальный элемент будет отображен на оверлейном слое в указанной позиции /// и будет следовать за курсором при обновлении через . /// public void ShowDragVisual(object dragVisual, Point position) { if (_overlay == null || _disposed) return; if (dragVisual is UIElement element) { _overlay.ShowDragVisual(element, position.X, position.Y); } } /// public void UpdateDragVisualPosition(object dragVisual, Point position) { if (_overlay == null || _disposed) return; if (dragVisual is UIElement element) { _overlay.UpdateDragVisualPosition(element, position.X, position.Y); } } /// public void HideDragVisual(object dragVisual) { if (_overlay == null || _disposed) return; if (dragVisual is UIElement element) { _overlay.HideDragVisual(element); } else { // Скрываем все визуальные элементы var current = _overlay.GetCurrentDragVisual(); if (current != null) { _overlay.HideDragVisual(current); } } } /// public void ShowDropAdorner(IDropVisualAdorner adorner) { if (_overlay == null || _disposed) return; if (adorner is DropPreviewAdorner dropAdorner) { // Для WinUI пока просто игнорируем } } /// public void HideDropAdorner(IDropVisualAdorner adorner) { if (_overlay == null || _disposed) return; _overlay.HideAllDropPreviews(); } /// public void Dispose() { if (_disposed) return; if (_overlay != null && _window?.Content is Panel panel) { panel.Children.Remove(_overlay); _overlay.ClearAllVisuals(); } _overlay = null; _window = null; _disposed = true; GC.SuppressFinalize(this); } }