доработана winUI реализация

This commit is contained in:
2026-01-25 06:29:37 +03:00
parent 0e050b452a
commit a902474345
8 changed files with 1594 additions and 452 deletions

View File

@@ -1,30 +1,64 @@
using Lattice.Core.DragDrop.Factories;
using Lattice.Core.DragDrop.Services;
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.
/// Фабрика для создания и настройки компонентов системы перетаскивания WinUI.
/// Предоставляет удобные методы для быстрой интеграции drag-and-drop функциональности
/// в приложениях WinUI с поддержкой различных сценариев использования.
/// </summary>
/// <remarks>
/// Эта фабрика упрощает интеграцию системы перетаскивания в WinUI приложения,
/// предоставляя готовые методы для наиболее распространенных сценариев использования.
/// <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 окна.
/// Создает и инициализирует менеджер перетаскивания для указанного окна WinUI.
/// </summary>
/// <param name="window">
/// Окно WinUI, для которого создается менеджер перетаскивания.
/// Не может быть null.
/// </param>
/// <returns>
/// Инициализированный экземпляр <see cref="WinUIDragDropManager"/>.
@@ -33,30 +67,38 @@ public static class WinUIDragDropFactory
/// Выбрасывается, когда <paramref name="window"/> равен null.
/// </exception>
/// <remarks>
/// Этот метод создает менеджер перетаскивания и настраивает его для работы с указанным окном.
/// Менеджер автоматически создает оверлей для визуальных элементов и подписывается на события.
/// </remarks>
/// <para>
/// Этот метод является основным способом получения менеджера перетаскивания.
/// Он создает (или возвращает существующий) экземпляр менеджера и инициализирует
/// его для работы с указанным окном.
/// </para>
/// <para>
/// Метод следует вызывать один раз при запуске приложения, обычно в конструкторе
/// главного окна или в методе <see cref="Application.OnLaunched"/>.
/// </para>
/// <example>
/// <code>
/// public partial class MainWindow : Window
/// {
/// private WinUIDragDropManager _dragDropManager;
///
/// public MainWindow()
/// {
/// InitializeComponent();
/// _dragDropManager = WinUIDragDropFactory.CreateManager(this);
/// 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;
manager.Initialize(window);
if (!manager.IsInitialized)
{
manager.Initialize(window);
}
return manager;
}
@@ -67,14 +109,34 @@ public static class WinUIDragDropFactory
/// Окно 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)
{
@@ -82,13 +144,20 @@ public static class WinUIDragDropFactory
throw new ArgumentNullException(nameof(window));
var manager = WinUIDragDropManager.Instance;
// Применяем настройки перед инициализацией
configure?.Invoke(manager);
manager.Initialize(window);
if (!manager.IsInitialized)
{
manager.Initialize(window);
}
return manager;
}
/// <summary>
/// Создает хост для визуальных элементов перетаскивания.
/// Создает хост для управления визуальными элементами перетаскивания.
/// </summary>
/// <param name="window">
/// Окно, к которому будет привязан хост.
@@ -96,9 +165,26 @@ public static class WinUIDragDropFactory
/// <returns>
/// Экземпляр <see cref="WinUIDragDropHost"/>, готовый к использованию.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="window"/> равен null.
/// </exception>
/// <remarks>
/// Хост управляет отображением визуальных элементов (drag-визуализация, drop-превью)
/// на оверлейном слое поверх основного содержимого окна.
/// <para>
/// Хост управляет отображением визуальных элементов во время операций перетаскивания,
/// включая drag-визуализации (элементы, следующие за курсором) и drop-превью
/// (подсветка областей сброса).
/// </para>
/// <para>
/// В большинстве случаев хост создается автоматически менеджером перетаскивания.
/// Этот метод полезен для продвинутых сценариев, когда требуется прямой контроль
/// над визуальной обратной связью.
/// </para>
/// <example>
/// <code>
/// var host = WinUIDragDropFactory.CreateHost(window);
/// // Настройка кастомной визуализации
/// </code>
/// </example>
/// </remarks>
public static WinUIDragDropHost CreateHost(Window window)
{
@@ -130,7 +216,21 @@ public static class WinUIDragDropFactory
/// Выбрасывается, если любой из параметров равен null.
/// </exception>
/// <remarks>
/// Созданное поведение необходимо прикрепить к элементу с помощью метода <see cref="WinUIDragSourceBehavior.Attach"/>.
/// <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,
@@ -160,7 +260,24 @@ public static class WinUIDragDropFactory
/// Выбрасывается, если любой из параметров равен null.
/// </exception>
/// <remarks>
/// Созданное поведение необходимо прикрепить к элементу с помощью метода <see cref="WinUIDropTargetBehavior.Attach"/>.
/// <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,
@@ -174,6 +291,93 @@ public static class WinUIDragDropFactory
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 Визуальные элементы
@@ -183,23 +387,44 @@ public static class WinUIDragDropFactory
/// </summary>
/// <param name="dragData">
/// Данные, которые будут отображены в визуальном элементе.
/// Могут быть любого типа, поддерживаемого системой перетаскивания.
/// </param>
/// <param name="opacity">
/// Прозрачность элемента (от 0.0 до 1.0).
/// Прозрачность элемента в диапазоне от 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,
Opacity = opacity
DragData = dragData ?? throw new ArgumentNullException(nameof(dragData)),
Opacity = Math.Clamp(opacity, 0.0, 1.0)
};
}
@@ -207,16 +432,40 @@ public static class WinUIDragDropFactory
/// Создает элемент предварительного просмотра для области сброса.
/// </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,
@@ -224,7 +473,7 @@ public static class WinUIDragDropFactory
{
var adorner = new DropPreviewAdorner
{
PreviewThickness = thickness
PreviewThickness = Math.Max(thickness, 0.0)
};
if (color.HasValue)
@@ -249,18 +498,35 @@ public static class WinUIDragDropFactory
/// Кортеж, содержащий менеджер перетаскивания и сервис перетаскивания.
/// </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 service = DragDropFactory.CreateDragDropService();
var manager = CreateManager(window);
return (manager, service);
return (manager, manager.DragDropService);
}
/// <summary>
/// Создает систему перетаскивания, оптимизированную для списков и коллекций.
/// Создает систему перетаскивания, оптимизированную для переупорядочивания элементов в списках.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
@@ -269,13 +535,45 @@ public static class WinUIDragDropFactory
/// Менеджер перетаскивания, настроенный для переупорядочивания элементов в списках.
/// </returns>
/// <remarks>
/// <para>
/// Эта конфигурация устанавливает оптимальные параметры для перетаскивания элементов
/// внутри списков (например, для изменения порядка элементов в ListView или ItemsControl).
/// внутри списков и коллекций, таких как:
/// <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);
});
@@ -283,7 +581,7 @@ public static class WinUIDragDropFactory
}
/// <summary>
/// Создает систему перетаскивания для файлов и документов.
/// Создает систему перетаскивания для работы с файлами и документами.
/// </summary>
/// <param name="window">
/// Главное окно приложения.
@@ -292,13 +590,37 @@ public static class WinUIDragDropFactory
/// Менеджер перетаскивания, настроенный для работы с файлами.
/// </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);
});
@@ -315,13 +637,39 @@ public static class WinUIDragDropFactory
/// Менеджер перетаскивания, настроенный для точного позиционирования.
/// </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);
});
@@ -344,11 +692,25 @@ public static class WinUIDragDropFactory
/// <param name="dragData">
/// Данные для перетаскивания. Если не указаны, будут использованы DataContext или Tag элемента.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="manager"/> или <paramref name="element"/> равны null.
/// </exception>
/// <remarks>
/// Этот метод является оберткой вокруг <see cref="WinUIDragDropManager.MakeDragSource"/>,
/// предоставляя более удобный API.
/// <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, Microsoft.UI.Xaml.FrameworkElement element, object dragData = null)
public static void SetupAsDragSource(WinUIDragDropManager manager, FrameworkElement element, object dragData = null)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
@@ -367,11 +729,25 @@ public static class WinUIDragDropFactory
/// <param name="element">
/// Элемент WinUI, который должен стать целью сброса.
/// </param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="manager"/> или <paramref name="element"/> равны null.
/// </exception>
/// <remarks>
/// Этот метод является оберткой вокруг <see cref="WinUIDragDropManager.MakeDropTarget"/>,
/// предоставляя более удобный API.
/// <para>
/// Этот метод является удобной оберткой вокруг <see cref="WinUIDragDropManager.MakeDropTarget"/>,
/// предоставляющей более лаконичный синтаксис.
/// </para>
/// <example>
/// <code>
/// // Использование вспомогательного метода
/// WinUIDragDropFactory.SetupAsDropTarget(manager, myDropArea);
///
/// // Эквивалентно:
/// manager.MakeDropTarget(myDropArea);
/// </code>
/// </example>
/// </remarks>
public static void SetupAsDropTarget(WinUIDragDropManager manager, Microsoft.UI.Xaml.FrameworkElement element)
public static void SetupAsDropTarget(WinUIDragDropManager manager, FrameworkElement element)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
@@ -388,20 +764,43 @@ public static class WinUIDragDropFactory
/// Менеджер перетаскивания.
/// </param>
/// <param name="container">
/// Контейнер (например, StackPanel или Grid), дочерние элементы которого можно переупорядочивать.
/// Контейнер (например, 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,
Microsoft.UI.Xaml.Controls.Panel container,
Func<Microsoft.UI.Xaml.FrameworkElement, object> childSelector = null)
FrameworkElement container,
Func<FrameworkElement, object> childSelector = null)
{
if (manager == null)
throw new ArgumentNullException(nameof(manager));
@@ -411,10 +810,50 @@ public static class WinUIDragDropFactory
// Настраиваем контейнер как цель сброса
manager.MakeDropTarget(container);
// Настраиваем все дочерние элементы как источники перетаскивания
foreach (var child in container.Children)
// Настраиваем дочерние элементы как источники перетаскивания
if (container is Panel panel)
{
if (child is Microsoft.UI.Xaml.FrameworkElement element)
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);
@@ -427,7 +866,7 @@ public static class WinUIDragDropFactory
#region Методы для работы с XAML
/// <summary>
/// Настраивает прикрепленные свойства для элемента источника перетаскивания.
/// Настраивает attached properties для элемента источника перетаскивания.
/// </summary>
/// <param name="element">
/// Элемент, который должен стать источником перетаскивания.
@@ -435,39 +874,76 @@ public static class WinUIDragDropFactory
/// <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(Microsoft.UI.Xaml.FrameworkElement element, object dragData)
public static void SetupDragSourceInXaml(FrameworkElement element, object dragData)
{
if (element == null)
throw new ArgumentNullException(nameof(element));
// Устанавливаем attached properties
element.SetValue(Behaviors.WinUIDragSourceBehavior.IsEnabledProperty, true);
element.SetValue(DragDropProperties.IsDragSourceProperty, true);
if (dragData != null)
{
element.SetValue(Behaviors.WinUIDragSourceBehavior.DragDataProperty, dragData);
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(Microsoft.UI.Xaml.FrameworkElement element)
public static void SetupDropTargetInXaml(FrameworkElement element)
{
if (element == null)
throw new ArgumentNullException(nameof(element));
element.SetValue(Behaviors.WinUIDropTargetBehavior.IsEnabledProperty, true);
element.SetValue(DragDropProperties.IsDropTargetProperty, true);
}
#endregion