DragAndDrop core
This commit is contained in:
213
Lattice.UI.DragDrop.WinUI/Controls/DragAdorner.cs
Normal file
213
Lattice.UI.DragDrop.WinUI/Controls/DragAdorner.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user