using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using System; using System.Linq; namespace Lattice.UI.DragDrop.WinUI.Extensions; /// /// Методы расширения для настройки перетаскивания в WinUI. /// public static class DragDropExtensions { #region Drag Source Extensions /// /// Делает элемент источником перетаскивания с указанными данными. /// public static void MakeDragSource(this UIElement element, object dragData) { Behaviors.WinUIDragSourceBehavior.SetDragData(element, dragData); Behaviors.WinUIDragSourceBehavior.SetIsEnabled(element, true); } /// /// Делает элемент источником перетаскивания с фабрикой данных. /// public static void MakeDragSource(this UIElement element, Func dataFactory) { element.MakeDragSource(dataFactory()); } /// /// Делает элемент источником перетаскивания с настраиваемыми параметрами. /// public static void MakeDragSource(this UIElement element, object dragData, Core.DragDrop.Enums.DragDropEffects allowedEffects, Func? canDrag = null) { element.MakeDragSource(dragData); element.SetAllowedEffects(allowedEffects); if (canDrag != null) { // Можно добавить кастомную логику проверки } } /// /// Удаляет возможность перетаскивания с элемента. /// public static void RemoveDragSource(this UIElement element) { Behaviors.WinUIDragSourceBehavior.SetIsEnabled(element, false); } /// /// Устанавливает разрешенные эффекты перетаскивания для элемента. /// public static void SetAllowedEffects(this UIElement element, Core.DragDrop.Enums.DragDropEffects effects) { Behaviors.WinUIDragSourceBehavior.SetAllowedEffects(element, effects); } /// /// Устанавливает смещение для визуального элемента перетаскивания. /// public static void SetDragVisualOffset(this UIElement element, double offsetX, double offsetY) { if (element is FrameworkElement frameworkElement) { frameworkElement.Tag = new Windows.Foundation.Point(offsetX, offsetY); } } #endregion #region Drop Target Extensions /// /// Делает элемент целью сброса. /// public static void MakeDropTarget(this UIElement element) { Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true); } /// /// Делает элемент целью сброса с фильтром типов данных. /// public static void MakeDropTarget(this UIElement element, params Type[] acceptedTypes) { Behaviors.WinUIDropTargetBehavior.SetAcceptsDataTypes(element, acceptedTypes); Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true); } /// /// Делает элемент целью сброса с обработчиком. /// public static void MakeDropTarget(this UIElement element, Core.DragDrop.Abstractions.IDropTarget handler) { Behaviors.WinUIDropTargetBehavior.SetDropHandler(element, handler); Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true); } /// /// Делает элемент целью сброса с полной настройкой. /// public static void MakeDropTarget(this UIElement element, Type[] acceptedTypes, Core.DragDrop.Abstractions.IDropTarget? handler = null, bool showVisualFeedback = true, Style? feedbackStyle = null) { if (acceptedTypes != null && acceptedTypes.Length > 0) { Behaviors.WinUIDropTargetBehavior.SetAcceptsDataTypes(element, acceptedTypes); } if (handler != null) { Behaviors.WinUIDropTargetBehavior.SetDropHandler(element, handler); } Behaviors.WinUIDropTargetBehavior.SetShowVisualFeedback(element, showVisualFeedback); if (feedbackStyle != null) { Behaviors.WinUIDropTargetBehavior.SetFeedbackStyle(element, feedbackStyle); } Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true); } /// /// Удаляет возможность сброса с элемента. /// public static void RemoveDropTarget(this UIElement element) { Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, false); } /// /// Устанавливает стиль визуальной обратной связи для цели сброса. /// public static void SetDropFeedbackStyle(this UIElement element, Style style) { Behaviors.WinUIDropTargetBehavior.SetFeedbackStyle(element, style); } /// /// Включает или выключает визуальную обратную связь при сбросе. /// public static void SetDropVisualFeedback(this UIElement element, bool enabled) { Behaviors.WinUIDropTargetBehavior.SetShowVisualFeedback(element, enabled); } #endregion #region Style Extensions /// /// Применяет стиль перетаскивания к элементу. /// public static void ApplyDragStyle(this Control control) { var style = Application.Current.Resources["DragEnabledStyle"] as Style; if (style != null) { control.Style = style; } } /// /// Применяет стиль цели сброса к элементу. /// public static void ApplyDropTargetStyle(this Control control) { var style = Application.Current.Resources["DropTargetStyle"] as Style; if (style != null) { control.Style = style; } } /// /// Включает визуальную обратную связь для элемента при перетаскивании. /// public static void EnableDragVisualFeedback(this Control control) { control.Loaded += (sender, e) => { // Убеждаемся, что у элемента есть визуальные состояния EnsureVisualStates(control); }; } /// /// Переключает визуальное состояние элемента для перетаскивания. /// public static void SetDragVisualState(this Control control, string stateName, bool useTransitions = true) { try { VisualStateManager.GoToState(control, stateName, useTransitions); } catch { // Если состояние не найдено, используем альтернативные методы switch (stateName) { case "Dragging": control.Opacity = 0.7; control.RenderTransform = new ScaleTransform { ScaleX = 0.95, ScaleY = 0.95 }; break; case "DragOver": control.Background = Application.Current.Resources["DragOverBackgroundBrush"] as Brush; control.BorderBrush = Application.Current.Resources["DragOverBorderBrush"] as Brush; break; case "Normal": control.ClearValue(Control.OpacityProperty); control.ClearValue(Control.RenderTransformProperty); control.ClearValue(Control.BackgroundProperty); control.ClearValue(Control.BorderBrushProperty); break; } } } #endregion #region Advanced Configuration /// /// Настраивает элемент для работы с сервисом перетаскивания. /// public static void ConfigureForDragDropService(this UIElement element, Core.DragDrop.Services.IDragDropService service, string? dropTargetGroup = null) { // Этот метод позволяет интегрировать элемент с централизованным сервисом // В реальной реализации нужно регистрировать элемент в сервисе } /// /// Создает контейнер с поддержкой перетаскивания для элементов. /// public static Panel CreateDragDropContainer( Orientation orientation = Orientation.Vertical, double spacing = 8, bool enableReordering = true) { var container = new StackPanel { Orientation = orientation, Spacing = spacing }; if (enableReordering) { // Настраиваем контейнер для переупорядочивания элементов container.MakeDropTarget(typeof(UIElement)); } return container; } /// /// Делает все дочерние элементы перетаскиваемыми. /// public static void MakeChildrenDraggable(this Panel container, Func dataSelector) { foreach (var child in container.Children.OfType()) { var data = dataSelector(child); child.MakeDragSource(data); } } #endregion #region Utility Methods /// /// Проверяет, является ли элемент источником перетаскивания. /// public static bool IsDragSource(this UIElement element) { return Behaviors.WinUIDragSourceBehavior.GetIsEnabled(element); } /// /// Проверяет, является ли элемент целью сброса. /// public static bool IsDropTarget(this UIElement element) { return Behaviors.WinUIDropTargetBehavior.GetIsEnabled(element); } /// /// Получает данные перетаскивания из элемента. /// public static object? GetDragData(this UIElement element) { return Behaviors.WinUIDragSourceBehavior.GetDragData(element); } #endregion #region Helper Methods private static void EnsureVisualStates(Control control) { // В WinUI 3 визуальные состояния должны быть определены в стиле элемента // Этот метод проверяет, что у элемента есть базовые визуальные состояния if (control.Template == null && control.Style == null) { // Применяем стандартный стиль, если у элемента нет своего control.ApplyDragStyle(); } } #endregion }