DragAndDrop core

This commit is contained in:
FrigaT
2026-01-18 16:33:35 +03:00
parent 9ea82af329
commit 79bdd8bc62
229 changed files with 21214 additions and 2494 deletions

View File

@@ -0,0 +1,327 @@
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;
/// <summary>
/// Методы расширения для настройки перетаскивания в WinUI.
/// </summary>
public static class DragDropExtensions
{
#region Drag Source Extensions
/// <summary>
/// Делает элемент источником перетаскивания с указанными данными.
/// </summary>
public static void MakeDragSource(this UIElement element, object dragData)
{
Behaviors.WinUIDragSourceBehavior.SetDragData(element, dragData);
Behaviors.WinUIDragSourceBehavior.SetIsEnabled(element, true);
}
/// <summary>
/// Делает элемент источником перетаскивания с фабрикой данных.
/// </summary>
public static void MakeDragSource(this UIElement element, Func<object> dataFactory)
{
element.MakeDragSource(dataFactory());
}
/// <summary>
/// Делает элемент источником перетаскивания с настраиваемыми параметрами.
/// </summary>
public static void MakeDragSource(this UIElement element,
object dragData,
Core.DragDrop.Enums.DragDropEffects allowedEffects,
Func<bool>? canDrag = null)
{
element.MakeDragSource(dragData);
element.SetAllowedEffects(allowedEffects);
if (canDrag != null)
{
// Можно добавить кастомную логику проверки
}
}
/// <summary>
/// Удаляет возможность перетаскивания с элемента.
/// </summary>
public static void RemoveDragSource(this UIElement element)
{
Behaviors.WinUIDragSourceBehavior.SetIsEnabled(element, false);
}
/// <summary>
/// Устанавливает разрешенные эффекты перетаскивания для элемента.
/// </summary>
public static void SetAllowedEffects(this UIElement element, Core.DragDrop.Enums.DragDropEffects effects)
{
Behaviors.WinUIDragSourceBehavior.SetAllowedEffects(element, effects);
}
/// <summary>
/// Устанавливает смещение для визуального элемента перетаскивания.
/// </summary>
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
/// <summary>
/// Делает элемент целью сброса.
/// </summary>
public static void MakeDropTarget(this UIElement element)
{
Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true);
}
/// <summary>
/// Делает элемент целью сброса с фильтром типов данных.
/// </summary>
public static void MakeDropTarget(this UIElement element, params Type[] acceptedTypes)
{
Behaviors.WinUIDropTargetBehavior.SetAcceptsDataTypes(element, acceptedTypes);
Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true);
}
/// <summary>
/// Делает элемент целью сброса с обработчиком.
/// </summary>
public static void MakeDropTarget(this UIElement element, Core.DragDrop.Abstractions.IDropTarget handler)
{
Behaviors.WinUIDropTargetBehavior.SetDropHandler(element, handler);
Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, true);
}
/// <summary>
/// Делает элемент целью сброса с полной настройкой.
/// </summary>
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);
}
/// <summary>
/// Удаляет возможность сброса с элемента.
/// </summary>
public static void RemoveDropTarget(this UIElement element)
{
Behaviors.WinUIDropTargetBehavior.SetIsEnabled(element, false);
}
/// <summary>
/// Устанавливает стиль визуальной обратной связи для цели сброса.
/// </summary>
public static void SetDropFeedbackStyle(this UIElement element, Style style)
{
Behaviors.WinUIDropTargetBehavior.SetFeedbackStyle(element, style);
}
/// <summary>
/// Включает или выключает визуальную обратную связь при сбросе.
/// </summary>
public static void SetDropVisualFeedback(this UIElement element, bool enabled)
{
Behaviors.WinUIDropTargetBehavior.SetShowVisualFeedback(element, enabled);
}
#endregion
#region Style Extensions
/// <summary>
/// Применяет стиль перетаскивания к элементу.
/// </summary>
public static void ApplyDragStyle(this Control control)
{
var style = Application.Current.Resources["DragEnabledStyle"] as Style;
if (style != null)
{
control.Style = style;
}
}
/// <summary>
/// Применяет стиль цели сброса к элементу.
/// </summary>
public static void ApplyDropTargetStyle(this Control control)
{
var style = Application.Current.Resources["DropTargetStyle"] as Style;
if (style != null)
{
control.Style = style;
}
}
/// <summary>
/// Включает визуальную обратную связь для элемента при перетаскивании.
/// </summary>
public static void EnableDragVisualFeedback(this Control control)
{
control.Loaded += (sender, e) =>
{
// Убеждаемся, что у элемента есть визуальные состояния
EnsureVisualStates(control);
};
}
/// <summary>
/// Переключает визуальное состояние элемента для перетаскивания.
/// </summary>
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
/// <summary>
/// Настраивает элемент для работы с сервисом перетаскивания.
/// </summary>
public static void ConfigureForDragDropService(this UIElement element,
Core.DragDrop.Services.IDragDropService service,
string? dropTargetGroup = null)
{
// Этот метод позволяет интегрировать элемент с централизованным сервисом
// В реальной реализации нужно регистрировать элемент в сервисе
}
/// <summary>
/// Создает контейнер с поддержкой перетаскивания для элементов.
/// </summary>
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;
}
/// <summary>
/// Делает все дочерние элементы перетаскиваемыми.
/// </summary>
public static void MakeChildrenDraggable(this Panel container, Func<UIElement, object> dataSelector)
{
foreach (var child in container.Children.OfType<UIElement>())
{
var data = dataSelector(child);
child.MakeDragSource(data);
}
}
#endregion
#region Utility Methods
/// <summary>
/// Проверяет, является ли элемент источником перетаскивания.
/// </summary>
public static bool IsDragSource(this UIElement element)
{
return Behaviors.WinUIDragSourceBehavior.GetIsEnabled(element);
}
/// <summary>
/// Проверяет, является ли элемент целью сброса.
/// </summary>
public static bool IsDropTarget(this UIElement element)
{
return Behaviors.WinUIDropTargetBehavior.GetIsEnabled(element);
}
/// <summary>
/// Получает данные перетаскивания из элемента.
/// </summary>
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
}

View File

@@ -0,0 +1,120 @@
using Lattice.Themes;
using Lattice.Themes.Core.Tokens;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Lattice.UI.DragDrop.WinUI.Extensions;
/// <summary>
/// Методы расширения для работы с темами в DragDrop.
/// </summary>
public static class ThemeExtensions
{
/// <summary>
/// Применяет стиль перетаскивания, основанный на токенах темы.
/// </summary>
public static void ApplyLatticeDragStyle(this Control control)
{
var style = Application.Current.Resources["Lattice.DragDrop.DragSourceStyle"] as Style;
if (style != null)
{
control.Style = style;
}
else
{
// Fallback на старый стиль
control.ApplyDragStyle();
}
}
/// <summary>
/// Применяет стиль цели сброса, основанный на токенах темы.
/// </summary>
public static void ApplyLatticeDropTargetStyle(this Control control)
{
var style = Application.Current.Resources["Lattice.DragDrop.DropTargetStyle"] as Style;
if (style != null)
{
control.Style = style;
}
else
{
// Fallback на старый стиль
control.ApplyDropTargetStyle();
}
}
/// <summary>
/// Переключает визуальное состояние элемента с использованием токенов темы.
/// </summary>
public static void SetLatticeDragVisualState(this Control control, string stateName, bool useTransitions = true)
{
try
{
VisualStateManager.GoToState(control, stateName, useTransitions);
}
catch
{
// Fallback на альтернативные методы с использованием токенов
var themeManager = ThemeManager.Current;
switch (stateName)
{
case "Dragging":
control.Opacity = themeManager.GetTokenValue<double?>(LatticeTokens.OpacityDrag) ?? 0.7;
control.RenderTransform = new Microsoft.UI.Xaml.Media.ScaleTransform
{
ScaleX = 0.95,
ScaleY = 0.95
};
break;
case "DragOver":
var dragOverBrush = themeManager.GetTokenValue<Microsoft.UI.Xaml.Media.Brush>(
LatticeTokens.BrushDragOverlay);
control.Background = dragOverBrush ??
Application.Current.Resources["Lattice.DragDrop.DragOverBackgroundBrush"] as Microsoft.UI.Xaml.Media.Brush;
break;
case "Normal":
control.ClearValue(Control.OpacityProperty);
control.ClearValue(Control.RenderTransformProperty);
control.ClearValue(Control.BackgroundProperty);
control.ClearValue(Control.BorderBrushProperty);
break;
}
}
}
/// <summary>
/// Получает значение токена для использования в DragDrop.
/// </summary>
public static T? GetDragDropToken<T>(this Control control, string tokenKey) where T : class
{
var themeManager = ThemeManager.Current;
return themeManager.GetTokenValue<T>(tokenKey);
}
/// <summary>
/// Создает DragAdorner с использованием токенов темы.
/// </summary>
public static Controls.DragAdorner CreateLatticeDragAdorner(object dragData)
{
return new Controls.DragAdorner
{
DragData = dragData,
Style = Application.Current.Resources["Lattice.DragDrop.DragSourceStyle"] as Style
};
}
/// <summary>
/// Создает DropPreviewAdorner с использованием токенов темы.
/// </summary>
public static Controls.DropPreviewAdorner CreateLatticeDropPreviewAdorner()
{
return new Controls.DropPreviewAdorner
{
Style = Application.Current.Resources[typeof(Controls.DropPreviewAdorner)] as Style
};
}
}