using Lattice.Core.Geometry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System;
namespace Lattice.UI.DragDrop.WinUI.Controls;
///
/// Визуальный элемент для отображения перетаскиваемого объекта.
///
public class DragAdorner : Control
{
///
/// Идентификатор свойства для данных перетаскивания.
///
public static readonly DependencyProperty DragDataProperty =
DependencyProperty.Register(
"DragData",
typeof(object),
typeof(DragAdorner),
new PropertyMetadata(null, OnDragDataChanged));
///
/// Идентификатор свойства для смещения относительно курсора.
///
public static readonly DependencyProperty OffsetProperty =
DependencyProperty.Register(
"Offset",
typeof(Point),
typeof(DragAdorner),
new PropertyMetadata(new Point(0, 0)));
///
/// Идентификатор свойства для угла поворота.
///
public static readonly DependencyProperty RotationAngleProperty =
DependencyProperty.Register(
"RotationAngle",
typeof(double),
typeof(DragAdorner),
new PropertyMetadata(0.0));
///
/// Идентификатор свойства для прозрачности.
///
public static readonly DependencyProperty OpacityLevelProperty =
DependencyProperty.Register(
"OpacityLevel",
typeof(double),
typeof(DragAdorner),
new PropertyMetadata(0.7));
private ContentPresenter? _contentPresenter;
///
/// Инициализирует новый экземпляр класса .
///
public DragAdorner()
{
DefaultStyleKey = typeof(DragAdorner);
// Устанавливаем свойства для корректного отображения поверх других элементов
IsHitTestVisible = false;
UseSystemFocusVisuals = false;
}
///
/// Получает или задает данные перетаскивания.
///
public object DragData
{
get => GetValue(DragDataProperty);
set => SetValue(DragDataProperty, value);
}
///
/// Получает или задает смещение относительно курсора.
///
public Point Offset
{
get => (Point)GetValue(OffsetProperty);
set => SetValue(OffsetProperty, value);
}
///
/// Получает или задает угол поворота.
///
public double RotationAngle
{
get => (double)GetValue(RotationAngleProperty);
set => SetValue(RotationAngleProperty, value);
}
///
/// Получает или задает уровень прозрачности.
///
public double OpacityLevel
{
get => (double)GetValue(OpacityLevelProperty);
set => SetValue(OpacityLevelProperty, value);
}
///
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = GetTemplateChild("PART_ContentPresenter") as ContentPresenter;
UpdateContent();
}
///
/// Обновляет позицию элемента относительно курсора.
///
/// Позиция курсора в экранных координатах.
public void UpdatePosition(Point cursorPosition)
{
var transform = new TranslateTransform
{
X = cursorPosition.X + Offset.X,
Y = cursorPosition.Y + Offset.Y
};
RenderTransform = new TransformGroup
{
Children =
{
transform,
new RotateTransform { Angle = RotationAngle }
}
};
}
///
/// Показывает элемент с анимацией.
///
public void Show()
{
Visibility = Visibility.Visible;
// Анимация появления
var animation = new Microsoft.UI.Xaml.Media.Animation.DoubleAnimation
{
From = 0,
To = OpacityLevel,
Duration = TimeSpan.FromMilliseconds(150),
EasingFunction = new Microsoft.UI.Xaml.Media.Animation.CubicEase
{
EasingMode = Microsoft.UI.Xaml.Media.Animation.EasingMode.EaseOut
}
};
var storyboard = new Microsoft.UI.Xaml.Media.Animation.Storyboard();
storyboard.Children.Add(animation);
Microsoft.UI.Xaml.Media.Animation.Storyboard.SetTarget(animation, this);
Microsoft.UI.Xaml.Media.Animation.Storyboard.SetTargetProperty(animation, "Opacity");
storyboard.Begin();
}
///
/// Скрывает элемент с анимацией.
///
public void Hide()
{
var animation = new Microsoft.UI.Xaml.Media.Animation.DoubleAnimation
{
From = Opacity,
To = 0,
Duration = TimeSpan.FromMilliseconds(100),
EasingFunction = new Microsoft.UI.Xaml.Media.Animation.CubicEase
{
EasingMode = Microsoft.UI.Xaml.Media.Animation.EasingMode.EaseIn
}
};
animation.Completed += (s, e) =>
{
Visibility = Visibility.Collapsed;
};
var storyboard = new Microsoft.UI.Xaml.Media.Animation.Storyboard();
storyboard.Children.Add(animation);
Microsoft.UI.Xaml.Media.Animation.Storyboard.SetTarget(animation, this);
Microsoft.UI.Xaml.Media.Animation.Storyboard.SetTargetProperty(animation, "Opacity");
storyboard.Begin();
}
private static void OnDragDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DragAdorner adorner)
{
adorner.UpdateContent();
}
}
private void UpdateContent()
{
if (_contentPresenter != null)
{
// Можно добавить DataTemplateSelector для разных типов данных
_contentPresenter.Content = DragData;
// Автоматически вычисляем смещение для приятного вида
if (DragData is FrameworkElement element)
{
Offset = new Point(-element.ActualWidth / 2, -element.ActualHeight / 2);
}
}
}
}