using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Xaml.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
///
/// A behavior that allows controls to be moved around the canvas using RenderTransform of .
///
public sealed class DragControlBehavior : StyledElementBehavior
{
///
/// Identifies the avalonia property.
///
public static readonly StyledProperty TargetControlProperty =
AvaloniaProperty.Register(nameof(TargetControl));
private Control? _parent;
private Point _previous;
///
/// Gets or sets the target control to be moved around instead of . This is a avalonia property.
///
[ResolveByName]
public Control? TargetControl
{
get => GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
///
protected override void OnAttachedToVisualTree()
{
var source = AssociatedObject;
if (source is not null)
{
source.PointerPressed += Source_PointerPressed;
}
}
///
protected override void OnDetachedFromVisualTree()
{
var source = AssociatedObject;
if (source is not null)
{
source.PointerPressed -= Source_PointerPressed;
}
_parent = null;
}
private void Source_PointerPressed(object? sender, PointerPressedEventArgs e)
{
var target = TargetControl ?? AssociatedObject;
if (target is not null)
{
_parent = target.Parent as Control;
if (!(target.RenderTransform is TranslateTransform))
{
target.RenderTransform = new TranslateTransform();
}
_previous = e.GetPosition(_parent);
if (_parent != null)
{
_parent.PointerMoved += Parent_PointerMoved;
_parent.PointerReleased += Parent_PointerReleased;
}
}
}
private void Parent_PointerMoved(object? sender, PointerEventArgs args)
{
var target = TargetControl ?? AssociatedObject;
if (target is not null)
{
var pos = args.GetPosition(_parent);
if (target.RenderTransform is TranslateTransform tr)
{
tr.X += pos.X - _previous.X;
tr.Y += pos.Y - _previous.Y;
}
_previous = pos;
}
}
private void Parent_PointerReleased(object? sender, PointerReleasedEventArgs e)
{
if (_parent is not null)
{
_parent.PointerMoved -= Parent_PointerMoved;
_parent.PointerReleased -= Parent_PointerReleased;
_parent = null;
}
}
}