Files
Lattice/Lattice.UI.DragDrop.WinUI/Services/WinUIDragDropHost.cs

160 lines
5.7 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.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;
/// <summary>
/// Хост для управления визуальными элементами перетаскивания в окне WinUI.
/// </summary>
/// <remarks>
/// <para>
/// Этот класс отвечает за отображение и управление визуальными элементами
/// во время операций перетаскивания, включая:
/// - Drag-визуализацию (элемент, следующий за курсором)
/// - Drop-превью (подсветка областей сброса)
/// </para>
/// <para>
/// Хост создает оверлейный слой поверх всего содержимого окна для корректного
/// отображения визуальных элементов поверх других UI-компонентов.
/// </para>
/// </remarks>
public sealed class WinUIDragDropHost : IDragDropHost, IDisposable
{
private DragDropOverlay? _overlay;
private Window? _window;
private bool _disposed;
/// <summary>
/// Инициализирует хост для работы с указанным окном.
/// </summary>
/// <param name="window">Окно, в котором будет работать перетаскивание.</param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="window"/> равен null.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// Выбрасывается, если хост уже был удален.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод создает оверлейный слой и добавляет его в визуальное дерево окна.
/// Если содержимое окна не является <see cref="Panel"/>, создается контейнер <see cref="Grid"/>.
/// </para>
/// <para>
/// Метод должен быть вызван один раз перед использованием других методов хоста.
/// </para>
/// </remarks>
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;
}
}
/// <summary>
/// Отображает визуальное представление перетаскиваемого элемента.
/// </summary>
/// <param name="dragVisual">Визуальный элемент для отображения.</param>
/// <param name="position">Позиция отображения в координатах экрана.</param>
/// <remarks>
/// Визуальный элемент будет отображен на оверлейном слое в указанной позиции
/// и будет следовать за курсором при обновлении через <see cref="UpdateDragVisualPosition"/>.
/// </remarks>
public void ShowDragVisual(object dragVisual, Point position)
{
if (_overlay == null || _disposed) return;
if (dragVisual is UIElement element)
{
_overlay.ShowDragVisual(element, position.X, position.Y);
}
}
/// <inheritdoc/>
public void UpdateDragVisualPosition(object dragVisual, Point position)
{
if (_overlay == null || _disposed) return;
if (dragVisual is UIElement element)
{
_overlay.UpdateDragVisualPosition(element, position.X, position.Y);
}
}
/// <inheritdoc/>
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);
}
}
}
/// <inheritdoc/>
public void ShowDropAdorner(IDropVisualAdorner adorner)
{
if (_overlay == null || _disposed) return;
if (adorner is DropPreviewAdorner dropAdorner)
{
// Для WinUI пока просто игнорируем
}
}
/// <inheritdoc/>
public void HideDropAdorner(IDropVisualAdorner adorner)
{
if (_overlay == null || _disposed) return;
_overlay.HideAllDropPreviews();
}
/// <inheritdoc/>
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);
}
}