Доработара WinUI реализация.

This commit is contained in:
2026-01-25 05:36:28 +03:00
parent bbb20edb03
commit 6ad7b5dcdb
20 changed files with 1089 additions and 1801 deletions

View File

@@ -7,14 +7,53 @@ using System;
namespace Lattice.UI.DragDrop.WinUI.Services;
public class WinUIDragDropHost : IDragDropHost
/// <summary>
/// Хост для управления визуальными элементами перетаскивания в окне WinUI.
/// </summary>
/// <remarks>
/// <para>
/// Этот класс отвечает за отображение и управление визуальными элементами
/// во время операций перетаскивания, включая:
/// - Drag-визуализацию (элемент, следующий за курсором)
/// - Drop-превью (подсветка областей сброса)
/// </para>
/// <para>
/// Хост создает оверлейный слой поверх всего содержимого окна для корректного
/// отображения визуальных элементов поверх других UI-компонентов.
/// </para>
/// </remarks>
public sealed class WinUIDragDropHost : IDragDropHost, IDisposable
{
private readonly DragDropOverlay _overlay;
private readonly Window _window;
private DragDropOverlay? _overlay;
private Window? _window;
private bool _disposed;
public WinUIDragDropHost(Window window)
/// <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();
// Добавляем оверлей в окно
@@ -22,33 +61,58 @@ public class WinUIDragDropHost : IDragDropHost
{
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
{
// Скрываем все, если передан null
// Скрываем все визуальные элементы
var current = _overlay.GetCurrentDragVisual();
if (current != null)
{
@@ -57,16 +121,40 @@ public class WinUIDragDropHost : IDragDropHost
}
}
/// <inheritdoc/>
public void ShowDropAdorner(IDropVisualAdorner adorner)
{
if (_overlay == null || _disposed) return;
if (adorner is DropPreviewAdorner dropAdorner)
{
// TODO: Показываем превью сброса
// Для 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);
}
}