Files
Lattice/Lattice.UI.DragDrop.WinUI/Factories/WinUIDragDropFactory.cs

950 lines
43 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.DragDrop.Services;
using Lattice.UI.DragDrop.WinUI.Behaviors;
using Lattice.UI.DragDrop.WinUI.Controls;
using Lattice.UI.DragDrop.WinUI.Services;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
namespace Lattice.UI.DragDrop.WinUI.Factories;
/// <summary>
/// Фабрика для создания и настройки компонентов системы перетаскивания WinUI.
/// Предоставляет удобные методы для быстрой интеграции drag-and-drop функциональности
/// в приложениях WinUI с поддержкой различных сценариев использования.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="WinUIDragDropFactory"/> служит высокоуровневым API для работы с системой
/// перетаскивания, инкапсулируя сложность инициализации и настройки компонентов.
/// </para>
/// <para>
/// Основные возможности фабрики:
/// <list type="bullet">
/// <item>Создание и инициализация менеджера перетаскивания</item>
/// <item>Генерация поведений для источников и целей перетаскивания</item>
/// <item>Создание визуальных элементов для обратной связи</item>
/// <item>Предварительные конфигурации для типовых сценариев</item>
/// <item>Вспомогательные методы для работы с XAML</item>
/// </list>
/// </para>
/// <para>
/// Фабрика поддерживает два подхода к использованию:
/// <list type="number">
/// <item><strong>Императивный подход</strong> - создание компонентов в коде C#</item>
/// <item><strong>Декларативный подход</strong> - использование attached properties в XAML</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Императивный подход
/// var manager = WinUIDragDropFactory.CreateManager(window);
/// manager.MakeDragSource(element, data);
/// manager.MakeDropTarget(dropArea);
///
/// // Декларативный подход (в XAML)
/// &lt;Border local:DragDropProperties.IsDragSource="True"
/// local:DragDropProperties.DragData="{Binding Item}" /&gt;
/// &lt;Border local:DragDropProperties.IsDropTarget="True" /&gt;
/// </code>
/// </example>
/// </remarks>
public static class WinUIDragDropFactory
{
#region Основные компоненты
/// <summary>
/// Создает и инициализирует менеджер перетаскивания для указанного окна WinUI.
/// </summary>
/// <param name="window">
/// Окно WinUI, для которого создается менеджер перетаскивания.
/// Не может быть null.
/// </param>
/// <returns>
/// Инициализированный экземпляр <see cref="WinUIDragDropManager"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, когда <paramref name="window"/> равен null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод является основным способом получения менеджера перетаскивания.
/// Он создает (или возвращает существующий) экземпляр менеджера и инициализирует
/// его для работы с указанным окном.
/// </para>
/// <para>
/// Метод следует вызывать один раз при запуске приложения, обычно в конструкторе
/// главного окна или в методе <see cref="Application.OnLaunched"/>.
/// </para>
/// <example>
/// <code>
/// public partial class MainWindow : Window
/// {
/// public MainWindow()
/// {
/// InitializeComponent();
/// var manager = WinUIDragDropFactory.CreateManager(this);
/// }
/// }
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropManager CreateManager(Window window)
{
if (window == null)
throw new ArgumentNullException(nameof(window));
var manager = WinUIDragDropManager.Instance;
if (!manager.IsInitialized)
{
manager.Initialize(window);
}
return manager;
}
/// <summary>
/// Создает и инициализирует менеджер перетаскивания с пользовательскими настройками.
/// </summary>
/// <param name="window">
/// Окно WinUI, для которого создается менеджер перетаскивания.
/// </param>
/// <param name="configure">
/// Делегат для настройки параметров менеджера перед инициализацией.
/// Передает экземпляр <see cref="WinUIDragDropManager"/> для конфигурации.
/// </param>
/// <returns>
/// Инициализированный экземпляр <see cref="WinUIDragDropManager"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, когда <paramref name="window"/> равен null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод позволяет настроить параметры менеджера перед его инициализацией,
/// что полезно для тонкой настройки поведения системы перетаскивания.
/// </para>
/// <para>
/// Доступные для настройки параметры включают:
/// <list type="bullet">
/// <item><see cref="WinUIDragDropManager.DragVisualOffset"/> - смещение визуального элемента</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// var manager = WinUIDragDropFactory.CreateManager(window, m =>
/// {
/// m.DragVisualOffset = new Point(-15, -15); // Ближе к курсору
/// });
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropManager CreateManager(Window window, Action<WinUIDragDropManager> configure)
{
if (window == null)
throw new ArgumentNullException(nameof(window));
var manager = WinUIDragDropManager.Instance;
// Применяем настройки перед инициализацией
configure?.Invoke(manager);
if (!manager.IsInitialized)
{
manager.Initialize(window);
}
return manager;
}
/// <summary>
/// Создает хост для управления визуальными элементами перетаскивания.
/// </summary>
/// <param name="window">
/// Окно, к которому будет привязан хост.
/// </param>
/// <returns>
/// Экземпляр <see cref="WinUIDragDropHost"/>, готовый к использованию.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="window"/> равен null.
/// </exception>
/// <remarks>
/// <para>
/// Хост управляет отображением визуальных элементов во время операций перетаскивания,
/// включая drag-визуализации (элементы, следующие за курсором) и drop-превью
/// (подсветка областей сброса).
/// </para>
/// <para>
/// В большинстве случаев хост создается автоматически менеджером перетаскивания.
/// Этот метод полезен для продвинутых сценариев, когда требуется прямой контроль
/// над визуальной обратной связью.
/// </para>
/// <example>
/// <code>
/// var host = WinUIDragDropFactory.CreateHost(window);
/// // Настройка кастомной визуализации
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropHost CreateHost(Window window)
{
if (window == null)
throw new ArgumentNullException(nameof(window));
var host = new WinUIDragDropHost();
host.Initialize(window);
return host;
}
#endregion
#region Поведения (Behaviors)
/// <summary>
/// Создает поведение источника перетаскивания для элемента WinUI.
/// </summary>
/// <param name="dragDropService">
/// Сервис перетаскивания, который будет управлять операциями.
/// </param>
/// <param name="host">
/// Хост для отображения визуальных элементов.
/// </param>
/// <returns>
/// Экземпляр <see cref="WinUIDragSourceBehavior"/>, готовый к прикреплению к элементу.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если любой из параметров равен null.
/// </exception>
/// <remarks>
/// <para>
/// Созданное поведение необходимо прикрепить к элементу с помощью метода
/// <see cref="WinUIDragSourceBehavior.Attach"/>.
/// </para>
/// <para>
/// Этот метод полезен для продвинутых сценариев, когда требуется создавать поведения
/// вручную, например, при динамическом создании элементов интерфейса.
/// </para>
/// <example>
/// <code>
/// // Создание поведения вручную
/// var behavior = WinUIDragDropFactory.CreateDragSourceBehavior(service, host);
/// behavior.Attach(element, data);
/// </code>
/// </example>
/// </remarks>
public static WinUIDragSourceBehavior CreateDragSourceBehavior(
IDragDropService dragDropService,
WinUIDragDropHost host)
{
if (dragDropService == null)
throw new ArgumentNullException(nameof(dragDropService));
if (host == null)
throw new ArgumentNullException(nameof(host));
return new WinUIDragSourceBehavior(dragDropService, host);
}
/// <summary>
/// Создает поведение цели сброса для элемента WinUI.
/// </summary>
/// <param name="dragDropService">
/// Сервис перетаскивания, который будет управлять операциями.
/// </param>
/// <param name="host">
/// Хост для отображения визуальных элементов.
/// </param>
/// <returns>
/// Экземпляр <see cref="WinUIDropTargetBehavior"/>, готовый к прикреплению к элементу.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если любой из параметров равен null.
/// </exception>
/// <remarks>
/// <para>
/// Созданное поведение необходимо прикрепить к элементу с помощью метода
/// <see cref="WinUIDropTargetBehavior.Attach"/>.
/// </para>
/// <para>
/// Поведение можно дополнительно настроить с помощью методов
/// <see cref="WinUIDropTargetBehavior.AcceptTypes"/> и
/// <see cref="WinUIDropTargetBehavior.AcceptFormats"/> для фильтрации
/// принимаемых данных.
/// </para>
/// <example>
/// <code>
/// // Создание поведения вручную
/// var behavior = WinUIDragDropFactory.CreateDropTargetBehavior(service, host);
/// behavior.AcceptTypes(typeof(string), typeof(MyModel));
/// behavior.Attach(dropArea);
/// </code>
/// </example>
/// </remarks>
public static WinUIDropTargetBehavior CreateDropTargetBehavior(
IDragDropService dragDropService,
WinUIDragDropHost host)
{
if (dragDropService == null)
throw new ArgumentNullException(nameof(dragDropService));
if (host == null)
throw new ArgumentNullException(nameof(host));
return new WinUIDropTargetBehavior(dragDropService, host);
}
/// <summary>
/// Создает поведение источника перетаскивания, используя сервисы из менеджера по умолчанию.
/// </summary>
/// <returns>
/// Экземпляр <see cref="WinUIDragSourceBehavior"/>, готовый к прикреплению к элементу.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Выбрасывается, если менеджер не инициализирован.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод использует <see cref="WinUIDragDropManager.Instance"/> для получения
/// сервиса перетаскивания и хоста, что упрощает создание поведений в контексте
/// уже инициализированной системы.
/// </para>
/// <para>
/// Перед использованием убедитесь, что менеджер инициализирован через метод
/// <see cref="CreateManager"/>.
/// </para>
/// <example>
/// <code>
/// // Инициализация менеджера
/// WinUIDragDropFactory.CreateManager(window);
///
/// // Создание поведения с использованием менеджера
/// var behavior = WinUIDragDropFactory.CreateDragSourceBehavior();
/// behavior.Attach(element, data);
/// </code>
/// </example>
/// </remarks>
public static WinUIDragSourceBehavior CreateDragSourceBehavior()
{
var manager = WinUIDragDropManager.Instance;
if (!manager.IsInitialized)
{
throw new InvalidOperationException(
"Менеджер не инициализирован. Вызовите CreateManager перед созданием поведений.");
}
return new WinUIDragSourceBehavior(manager.DragDropService, manager.Host);
}
/// <summary>
/// Создает поведение цели сброса, используя сервисы из менеджера по умолчанию.
/// </summary>
/// <returns>
/// Экземпляр <see cref="WinUIDropTargetBehavior"/>, готовый к прикреплению к элементу.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Выбрасывается, если менеджер не инициализирован.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод использует <see cref="WinUIDragDropManager.Instance"/> для получения
/// сервиса перетаскивания и хоста, что упрощает создание поведений в контексте
/// уже инициализированной системы.
/// </para>
/// <para>
/// Поведение можно дополнительно настроить с помощью методов
/// <see cref="WinUIDropTargetBehavior.AcceptTypes"/> и
/// <see cref="WinUIDropTargetBehavior.AcceptFormats"/> для фильтрации
/// принимаемых данных.
/// </para>
/// <example>
/// <code>
/// // Инициализация менеджера
/// WinUIDragDropFactory.CreateManager(window);
///
/// // Создание поведения с использованием менеджера
/// var behavior = WinUIDragDropFactory.CreateDropTargetBehavior();
/// behavior.AcceptTypes(typeof(string));
/// behavior.Attach(dropArea);
/// </code>
/// </example>
/// </remarks>
public static WinUIDropTargetBehavior CreateDropTargetBehavior()
{
var manager = WinUIDragDropManager.Instance;
if (!manager.IsInitialized)
{
throw new InvalidOperationException(
"Менеджер не инициализирован. Вызовите CreateManager перед созданием поведений.");
}
return new WinUIDropTargetBehavior(manager.DragDropService, manager.Host);
}
#endregion
#region Визуальные элементы
/// <summary>
/// Создает визуальный элемент для отображения во время перетаскивания.
/// </summary>
/// <param name="dragData">
/// Данные, которые будут отображены в визуальном элементе.
/// Могут быть любого типа, поддерживаемого системой перетаскивания.
/// </param>
/// <param name="opacity">
/// Прозрачность элемента в диапазоне от 0.0 (полностью прозрачный) до 1.0 (полностью непрозрачный).
/// Значение по умолчанию: 0.8.
/// </param>
/// <returns>
/// Экземпляр <see cref="DragAdorner"/>, настроенный для отображения указанных данных.
/// </returns>
/// <remarks>
/// <para>
/// Созданный элемент можно использовать с методом <see cref="WinUIDragDropHost.ShowDragVisual"/>
/// для отображения во время операции перетаскивания.
/// </para>
/// <para>
/// Элемент автоматически адаптирует отображение в зависимости от типа данных:
/// <list type="bullet">
/// <item>Для строк отображается текстовое представление</item>
/// <item>Для изображений отображается миниатюра</item>
/// <item>Для пользовательских объектов используется DataTemplate или ToString()</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Создание визуального элемента
/// var adorner = WinUIDragDropFactory.CreateDragAdorner("Текст для перетаскивания");
///
/// // Отображение во время перетаскивания
/// host.ShowDragVisual(adorner, position);
/// </code>
/// </example>
/// </remarks>
public static DragAdorner CreateDragAdorner(object dragData, double opacity = 0.8)
{
return new DragAdorner
{
DragData = dragData ?? throw new ArgumentNullException(nameof(dragData)),
Opacity = Math.Clamp(opacity, 0.0, 1.0)
};
}
/// <summary>
/// Создает элемент предварительного просмотра для области сброса.
/// </summary>
/// <param name="color">
/// Цвет подсветки области. Если не указан, используется системный цвет акцента.
/// </param>
/// <param name="thickness">
/// Толщина границы подсветки в пикселях.
/// Значение по умолчанию: 2.0.
/// </param>
/// <returns>
/// Экземпляр <see cref="DropPreviewAdorner"/>, готовый к отображению.
/// </returns>
/// <remarks>
/// <para>
/// Этот элемент используется для визуального указания области, на которую можно
/// сбросить данные. Он отображается как подсветка границ целевого элемента с
/// поддержкой анимации появления и скрытия.
/// </para>
/// <para>
/// Элемент автоматически адаптирует свой внешний вид в зависимости от состояния:
/// <list type="bullet">
/// <item><strong>Normal</strong> - стандартное состояние</item>
/// <item><strong>Highlighted</strong> - подсветка при наведении</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Создание элемента подсветки
/// var preview = WinUIDragDropFactory.CreateDropPreviewAdorner(
/// Colors.Blue, // Цвет
/// 3.0 // Толщина границы
/// );
///
/// // Отображение подсветки
/// preview.Show(bounds);
/// </code>
/// </example>
/// </remarks>
public static DropPreviewAdorner CreateDropPreviewAdorner(
Windows.UI.Color? color = null,
double thickness = 2.0)
{
var adorner = new DropPreviewAdorner
{
PreviewThickness = Math.Max(thickness, 0.0)
};
if (color.HasValue)
{
adorner.PreviewColor = color.Value;
}
return adorner;
}
#endregion
#region Готовые конфигурации для типовых сценариев
/// <summary>
/// Создает полную систему перетаскивания для WinUI приложения.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
/// </param>
/// <returns>
/// Кортеж, содержащий менеджер перетаскивания и сервис перетаскивания.
/// </returns>
/// <remarks>
/// <para>
/// Этот метод создает все необходимые компоненты для работы перетаскивания в приложении
/// и возвращает их для дальнейшего использования.
/// </para>
/// <para>
/// Возвращаемый сервис можно использовать для создания дополнительных источников и целей
/// или для низкоуровневого управления операциями перетаскивания.
/// </para>
/// <example>
/// <code>
/// // Создание полной системы
/// var (manager, service) = WinUIDragDropFactory.CreateCompleteSystem(window);
///
/// // Использование менеджера для настройки элементов
/// manager.MakeDragSource(element, data);
///
/// // Использование сервиса для расширенного управления
/// var stats = service.GetStats();
/// </code>
/// </example>
/// </remarks>
public static (WinUIDragDropManager Manager, IDragDropService Service) CreateCompleteSystem(Window window)
{
var manager = CreateManager(window);
return (manager, manager.DragDropService);
}
/// <summary>
/// Создает систему перетаскивания, оптимизированную для переупорядочивания элементов в списках.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
/// </param>
/// <returns>
/// Менеджер перетаскивания, настроенный для переупорядочивания элементов в списках.
/// </returns>
/// <remarks>
/// <para>
/// Эта конфигурация устанавливает оптимальные параметры для перетаскивания элементов
/// внутри списков и коллекций, таких как:
/// <list type="bullet">
/// <item>Изменение порядка элементов в ListView</item>
/// <item>Перемещение элементов между ItemsControl</item>
/// <item>Сортировка элементов в коллекциях</item>
/// </list>
/// </para>
/// <para>
/// Особенности конфигурации:
/// <list type="bullet">
/// <item>Уменьшенный порог начала перетаскивания для более быстрого отклика</item>
/// <item>Смещение визуального элемента для лучшего визуального выравнивания</item>
/// <item>Оптимизированная визуальная обратная связь</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Создание системы для переупорядочивания списков
/// var manager = WinUIDragDropFactory.CreateListReorderSystem(window);
///
/// // Настройка ListView для переупорядочивания
/// foreach (var item in myListView.Items)
/// {
/// if (item is FrameworkElement element)
/// {
/// manager.MakeDragSource(element, element.DataContext);
/// }
/// }
/// manager.MakeDropTarget(myListView);
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropManager CreateListReorderSystem(Window window)
{
var manager = CreateManager(window, m =>
{
// Уменьшенное смещение для лучшего визуального выравнивания в списках
m.DragVisualOffset = new Core.Geometry.Point(-15, -15);
});
return manager;
}
/// <summary>
/// Создает систему перетаскивания для работы с файлами и документами.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
/// </param>
/// <returns>
/// Менеджер перетаскивания, настроенный для работы с файлами.
/// </returns>
/// <remarks>
/// <para>
/// Эта конфигурация оптимизирована для сценариев работы с файлами:
/// <list type="bullet">
/// <item>Перетаскивание файлов из проводника в приложение</item>
/// <item>Перемещение файлов между элементами интерфейса</item>
/// <item>Работа с большими объемами данных</item>
/// </list>
/// </para>
/// <para>
/// Особенности конфигурации:
/// <list type="bullet">
/// <item>Увеличенный порог перетаскивания для предотвращения случайных операций</item>
/// <item>Специальные визуальные эффекты, характерные для файловых операций</item>
/// <item>Оптимизация для работы с внешними источниками данных</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Создание системы для работы с файлами
/// var manager = WinUIDragDropFactory.CreateFileDragDropSystem(window);
///
/// // Настройка области для приема файлов
/// manager.MakeDropTarget(fileDropArea);
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropManager CreateFileDragDropSystem(Window window)
{
var manager = CreateManager(window, m =>
{
// Увеличенное смещение для файлов (имитация "переноса" файла)
m.DragVisualOffset = new Core.Geometry.Point(-25, -25);
});
return manager;
}
/// <summary>
/// Создает систему перетаскивания для графических редакторов и инструментов дизайна.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
/// </param>
/// <returns>
/// Менеджер перетаскивания, настроенный для точного позиционирования.
/// </returns>
/// <remarks>
/// <para>
/// Эта конфигурация оптимизирована для приложений, требующих высокой точности
/// позиционирования, таких как:
/// <list type="bullet">
/// <item>Графические редакторы (Photoshop, Figma)</item>
/// <item>Инструменты проектирования интерфейсов</item>
/// <item>CAD-системы и приложения для 3D-моделирования</item>
/// </list>
/// </para>
/// <para>
/// Особенности конфигурации:
/// <list type="bullet">
/// <item>Минимальный порог начала перетаскивания для максимальной точности</item>
/// <item>Минималистичная визуализация для уменьшения визуального шума</item>
/// <item>Оптимизация для работы с высокоточными устройствами ввода (графические планшеты)</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Создание системы для графического редактора
/// var manager = WinUIDragDropFactory.CreateDesignToolSystem(window);
///
/// // Настройка инструментов для перетаскивания
/// manager.MakeDragSource(toolIcon, toolData);
/// manager.MakeDropTarget(canvas);
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropManager CreateDesignToolSystem(Window window)
{
var manager = CreateManager(window, m =>
{
// Минимальное смещение для точного позиционирования
m.DragVisualOffset = new Core.Geometry.Point(-10, -10);
});
return manager;
}
#endregion
#region Вспомогательные методы
/// <summary>
/// Настраивает элемент как источник перетаскивания с использованием указанного менеджера.
/// </summary>
/// <param name="manager">
/// Менеджер перетаскивания, который будет управлять операцией.
/// </param>
/// <param name="element">
/// Элемент WinUI, который должен стать источником перетаскивания.
/// </param>
/// <param name="dragData">
/// Данные для перетаскивания. Если не указаны, будут использованы DataContext или Tag элемента.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="manager"/> или <paramref name="element"/> равны null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод является удобной оберткой вокруг <see cref="WinUIDragDropManager.MakeDragSource"/>,
/// предоставляющей более лаконичный синтаксис.
/// </para>
/// <example>
/// <code>
/// // Использование вспомогательного метода
/// WinUIDragDropFactory.SetupAsDragSource(manager, myElement, myData);
///
/// // Эквивалентно:
/// manager.MakeDragSource(myElement, myData);
/// </code>
/// </example>
/// </remarks>
public static void SetupAsDragSource(WinUIDragDropManager manager, FrameworkElement element, object dragData = null)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
if (element == null)
throw new ArgumentNullException(nameof(element));
manager.MakeDragSource(element, dragData);
}
/// <summary>
/// Настраивает элемент как цель сброса с использованием указанного менеджера.
/// </summary>
/// <param name="manager">
/// Менеджер перетаскивания, который будет управлять операцией.
/// </param>
/// <param name="element">
/// Элемент WinUI, который должен стать целью сброса.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="manager"/> или <paramref name="element"/> равны null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод является удобной оберткой вокруг <see cref="WinUIDragDropManager.MakeDropTarget"/>,
/// предоставляющей более лаконичный синтаксис.
/// </para>
/// <example>
/// <code>
/// // Использование вспомогательного метода
/// WinUIDragDropFactory.SetupAsDropTarget(manager, myDropArea);
///
/// // Эквивалентно:
/// manager.MakeDropTarget(myDropArea);
/// </code>
/// </example>
/// </remarks>
public static void SetupAsDropTarget(WinUIDragDropManager manager, FrameworkElement element)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
if (element == null)
throw new ArgumentNullException(nameof(element));
manager.MakeDropTarget(element);
}
/// <summary>
/// Настраивает контейнер для поддержки переупорядочивания дочерних элементов.
/// </summary>
/// <param name="manager">
/// Менеджер перетаскивания.
/// </param>
/// <param name="container">
/// Контейнер (например, StackPanel, Grid или ItemsControl), дочерние элементы которого можно переупорядочивать.
/// </param>
/// <param name="childSelector">
/// Функция для получения данных перетаскивания из дочернего элемента.
/// Если не указана, используются DataContext дочерних элементов.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="manager"/> или <paramref name="container"/> равны null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод автоматически настраивает все дочерние элементы контейнера как источники перетаскивания,
/// а сам контейнер — как цель сброса, создавая функциональность переупорядочивания элементов.
/// </para>
/// <para>
/// Поддерживаемые типы контейнеров:
/// <list type="bullet">
/// <item><see cref="Panel"/> и его производные (StackPanel, Grid, Canvas)</item>
/// <item><see cref="ItemsControl"/> и его производные (ListView, ListBox)</item>
/// <item>Любые другие контейнеры с коллекцией дочерних элементов</item>
/// </list>
/// </para>
/// <example>
/// <code>
/// // Настройка StackPanel для переупорядочивания дочерних элементов
/// WinUIDragDropFactory.SetupReorderContainer(manager, myStackPanel);
///
/// // С кастомным селектором данных
/// WinUIDragDropFactory.SetupReorderContainer(manager, myListView,
/// element => ((FrameworkElement)element).DataContext);
/// </code>
/// </example>
/// </remarks>
public static void SetupReorderContainer(
WinUIDragDropManager manager,
FrameworkElement container,
Func<FrameworkElement, object> childSelector = null)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
if (container == null)
throw new ArgumentNullException(nameof(container));
// Настраиваем контейнер как цель сброса
manager.MakeDropTarget(container);
// Настраиваем дочерние элементы как источники перетаскивания
if (container is Panel panel)
{
SetupPanelChildren(manager, panel, childSelector);
}
else if (container is ItemsControl itemsControl)
{
SetupItemsControlChildren(manager, itemsControl, childSelector);
}
}
/// <summary>
/// Настраивает дочерние элементы Panel как источники перетаскивания.
/// </summary>
private static void SetupPanelChildren(
WinUIDragDropManager manager,
Panel panel,
Func<FrameworkElement, object> childSelector)
{
foreach (var child in panel.Children)
{
if (child is FrameworkElement element)
{
var data = childSelector?.Invoke(element) ?? element.DataContext ?? element.Tag;
manager.MakeDragSource(element, data);
}
}
}
/// <summary>
/// Настраивает элементы ItemsControl как источники перетаскивания.
/// </summary>
private static void SetupItemsControlChildren(
WinUIDragDropManager manager,
ItemsControl itemsControl,
Func<FrameworkElement, object> childSelector)
{
// Для ItemsControl нам нужно работать с ItemContainerGenerator
// В реальной реализации здесь должна быть более сложная логика
// для обработки виртуализации и динамических элементов
foreach (var item in itemsControl.Items)
{
if (item is FrameworkElement element)
{
var data = childSelector?.Invoke(element) ?? element.DataContext ?? element.Tag;
manager.MakeDragSource(element, data);
}
}
}
#endregion
#region Методы для работы с XAML
/// <summary>
/// Настраивает attached properties для элемента источника перетаскивания.
/// </summary>
/// <param name="element">
/// Элемент, который должен стать источником перетаскивания.
/// </param>
/// <param name="dragData">
/// Данные для перетаскивания.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="element"/> равен null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод устанавливает attached properties, которые активируют поведение перетаскивания
/// при использовании в XAML. Эквивалентно установке свойств IsDragSource и DragData в XAML.
/// </para>
/// <para>
/// Метод полезен для динамической настройки элементов в коде C# при сохранении
/// декларативного стиля программирования.
/// </para>
/// <example>
/// <code>
/// // Настройка элемента в коде C#
/// WinUIDragDropFactory.SetupDragSourceInXaml(myElement, myData);
///
/// // Эквивалентно в XAML:
/// &lt;Border local:DragDropProperties.IsDragSource="True"
/// local:DragDropProperties.DragData="{Binding MyData}" /&gt;
/// </code>
/// </example>
/// </remarks>
public static void SetupDragSourceInXaml(FrameworkElement element, object dragData)
{
if (element == null)
throw new ArgumentNullException(nameof(element));
// Устанавливаем attached properties
element.SetValue(DragDropProperties.IsDragSourceProperty, true);
if (dragData != null)
{
element.SetValue(DragDropProperties.DragDataProperty, dragData);
}
}
/// <summary>
/// Настраивает attached properties для элемента цели сброса.
/// </summary>
/// <param name="element">
/// Элемент, который должен стать целью сброса.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="element"/> равен null.
/// </exception>
/// <remarks>
/// <para>
/// Этот метод устанавливает attached properties, которые активируют поведение цели сброса
/// при использовании в XAML. Эквивалентно установке свойства IsDropTarget в XAML.
/// </para>
/// <para>
/// Метод полезен для динамической настройки элементов в коде C# при сохранении
/// декларативного стиля программирования.
/// </para>
/// <example>
/// <code>
/// // Настройка элемента в коде C#
/// WinUIDragDropFactory.SetupDropTargetInXaml(myDropArea);
///
/// // Эквивалентно в XAML:
/// &lt;Border local:DragDropProperties.IsDropTarget="True" /&gt;
/// </code>
/// </example>
/// </remarks>
public static void SetupDropTargetInXaml(FrameworkElement element)
{
if (element == null)
throw new ArgumentNullException(nameof(element));
element.SetValue(DragDropProperties.IsDropTargetProperty, true);
}
#endregion
}