213 lines
6.9 KiB
C#
213 lines
6.9 KiB
C#
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;
|
||
|
||
/// <summary>
|
||
/// Визуальный элемент для отображения перетаскиваемого объекта.
|
||
/// </summary>
|
||
public class DragAdorner : Control
|
||
{
|
||
/// <summary>
|
||
/// Идентификатор свойства для данных перетаскивания.
|
||
/// </summary>
|
||
public static readonly DependencyProperty DragDataProperty =
|
||
DependencyProperty.Register(
|
||
"DragData",
|
||
typeof(object),
|
||
typeof(DragAdorner),
|
||
new PropertyMetadata(null, OnDragDataChanged));
|
||
|
||
/// <summary>
|
||
/// Идентификатор свойства для смещения относительно курсора.
|
||
/// </summary>
|
||
public static readonly DependencyProperty OffsetProperty =
|
||
DependencyProperty.Register(
|
||
"Offset",
|
||
typeof(Point),
|
||
typeof(DragAdorner),
|
||
new PropertyMetadata(new Point(0, 0)));
|
||
|
||
/// <summary>
|
||
/// Идентификатор свойства для угла поворота.
|
||
/// </summary>
|
||
public static readonly DependencyProperty RotationAngleProperty =
|
||
DependencyProperty.Register(
|
||
"RotationAngle",
|
||
typeof(double),
|
||
typeof(DragAdorner),
|
||
new PropertyMetadata(0.0));
|
||
|
||
/// <summary>
|
||
/// Идентификатор свойства для прозрачности.
|
||
/// </summary>
|
||
public static readonly DependencyProperty OpacityLevelProperty =
|
||
DependencyProperty.Register(
|
||
"OpacityLevel",
|
||
typeof(double),
|
||
typeof(DragAdorner),
|
||
new PropertyMetadata(0.7));
|
||
|
||
private ContentPresenter? _contentPresenter;
|
||
|
||
/// <summary>
|
||
/// Инициализирует новый экземпляр класса <see cref="DragAdorner"/>.
|
||
/// </summary>
|
||
public DragAdorner()
|
||
{
|
||
DefaultStyleKey = typeof(DragAdorner);
|
||
|
||
// Устанавливаем свойства для корректного отображения поверх других элементов
|
||
IsHitTestVisible = false;
|
||
UseSystemFocusVisuals = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает или задает данные перетаскивания.
|
||
/// </summary>
|
||
public object DragData
|
||
{
|
||
get => GetValue(DragDataProperty);
|
||
set => SetValue(DragDataProperty, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает или задает смещение относительно курсора.
|
||
/// </summary>
|
||
public Point Offset
|
||
{
|
||
get => (Point)GetValue(OffsetProperty);
|
||
set => SetValue(OffsetProperty, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает или задает угол поворота.
|
||
/// </summary>
|
||
public double RotationAngle
|
||
{
|
||
get => (double)GetValue(RotationAngleProperty);
|
||
set => SetValue(RotationAngleProperty, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает или задает уровень прозрачности.
|
||
/// </summary>
|
||
public double OpacityLevel
|
||
{
|
||
get => (double)GetValue(OpacityLevelProperty);
|
||
set => SetValue(OpacityLevelProperty, value);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
protected override void OnApplyTemplate()
|
||
{
|
||
base.OnApplyTemplate();
|
||
|
||
_contentPresenter = GetTemplateChild("PART_ContentPresenter") as ContentPresenter;
|
||
UpdateContent();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обновляет позицию элемента относительно курсора.
|
||
/// </summary>
|
||
/// <param name="cursorPosition">Позиция курсора в экранных координатах.</param>
|
||
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 }
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Показывает элемент с анимацией.
|
||
/// </summary>
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Скрывает элемент с анимацией.
|
||
/// </summary>
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
} |