Files
Lattice/Lattice.UI.DragDrop.WinUI/Controls/DragAdorner.cs
2026-01-18 16:33:35 +03:00

213 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}
}