using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;
namespace Avalonia.Xaml.Interactions.Draggable;
///
///
///
public class GridDragBehavior : StyledElementBehavior
{
///
///
///
public static readonly StyledProperty CopyColumnProperty =
AvaloniaProperty.Register(nameof(CopyColumn), true);
///
///
///
public static readonly StyledProperty CopyRowProperty =
AvaloniaProperty.Register(nameof(CopyRow), true);
///
///
///
public static readonly StyledProperty CopyColumnSpanProperty =
AvaloniaProperty.Register(nameof(CopyColumnSpan));
///
///
///
public static readonly StyledProperty CopyRowSpanProperty =
AvaloniaProperty.Register(nameof(CopyRowSpan));
private bool _enableDrag;
private Control? _parent;
private Control? _draggedContainer;
private Control? _adorner;
private bool _captured;
///
///
///
public bool CopyColumn
{
get => GetValue(CopyColumnProperty);
set => SetValue(CopyColumnProperty, value);
}
///
///
///
public bool CopyRow
{
get => GetValue(CopyRowProperty);
set => SetValue(CopyRowProperty, value);
}
///
///
///
public bool CopyColumnSpan
{
get => GetValue(CopyColumnSpanProperty);
set => SetValue(CopyColumnSpanProperty, value);
}
///
///
///
public bool CopyRowSpan
{
get => GetValue(CopyRowSpanProperty);
set => SetValue(CopyRowSpanProperty, value);
}
///
protected override void OnAttachedToVisualTree()
{
if (AssociatedObject is not null)
{
AssociatedObject.AddHandler(InputElement.PointerReleasedEvent, Released, RoutingStrategies.Tunnel);
AssociatedObject.AddHandler(InputElement.PointerPressedEvent, Pressed, RoutingStrategies.Tunnel);
AssociatedObject.AddHandler(InputElement.PointerMovedEvent, Moved, RoutingStrategies.Tunnel);
AssociatedObject.AddHandler(InputElement.PointerCaptureLostEvent, CaptureLost, RoutingStrategies.Tunnel);
}
}
///
protected override void OnDetachedFromVisualTree()
{
if (AssociatedObject is not null)
{
AssociatedObject.RemoveHandler(InputElement.PointerReleasedEvent, Released);
AssociatedObject.RemoveHandler(InputElement.PointerPressedEvent, Pressed);
AssociatedObject.RemoveHandler(InputElement.PointerMovedEvent, Moved);
AssociatedObject.RemoveHandler(InputElement.PointerCaptureLostEvent, CaptureLost);
}
}
private void AddAdorner(Control control)
{
var layer = AdornerLayer.GetAdornerLayer(control);
if (layer is null)
{
return;
}
_adorner = new SelectionAdorner()
{
[AdornerLayer.AdornedElementProperty] = control
};
((ISetLogicalParent) _adorner).SetParent(control);
layer.Children.Add(_adorner);
}
private void RemoveAdorner(Control control)
{
var layer = AdornerLayer.GetAdornerLayer(control);
if (layer is null || _adorner is null)
{
return;
}
layer.Children.Remove(_adorner);
((ISetLogicalParent) _adorner).SetParent(null);
_adorner = null;
}
private void Pressed(object? sender, PointerPressedEventArgs e)
{
var properties = e.GetCurrentPoint(AssociatedObject).Properties;
if (properties.IsLeftButtonPressed
&& AssociatedObject?.Parent is Control parent)
{
_enableDrag = true;
_parent = parent;
_draggedContainer = AssociatedObject;
SetDraggingPseudoClasses(_draggedContainer, true);
// AddAdorner(_draggedContainer);
_captured = true;
}
}
private void Released(object? sender, PointerReleasedEventArgs e)
{
if (_captured)
{
if (e.InitialPressMouseButton == MouseButton.Left)
{
Released();
}
_captured = false;
}
}
private void CaptureLost(object? sender, PointerCaptureLostEventArgs e)
{
Released();
_captured = false;
}
private void Moved(object? sender, PointerEventArgs e)
{
var properties = e.GetCurrentPoint(AssociatedObject).Properties;
if (_captured
&& properties.IsLeftButtonPressed)
{
if (_parent is null || _draggedContainer is null || !_enableDrag)
{
return;
}
var position = e.GetPosition(_parent);
Control? target = null;
if (_parent is Grid grid)
{
foreach (var child in grid.Children)
{
if (Equals(child, _draggedContainer))
{
continue;
}
if (child.Bounds.Contains(position) && child is Control control)
{
target = control;
}
}
}
else if (_parent is ItemsControl itemsControl)
{
foreach (var control in itemsControl.GetRealizedContainers())
{
if (control is null)
{
continue;
}
if (Equals(control, _draggedContainer))
{
continue;
}
if (control.Bounds.Contains(position))
{
target = control;
}
}
}
else
{
return;
}
if (target is null)
{
return;
}
var copyColumn = CopyColumn;
var copyRow = CopyRow;
var copyColumnSpan = CopyColumnSpan;
var copyRowSpan = CopyRowSpan;
var sourceColumn = Grid.GetColumn(_draggedContainer);
var sourceRow = Grid.GetRow(_draggedContainer);
var sourceColumnSpan = Grid.GetColumnSpan(_draggedContainer);
var sourceRowSpan = Grid.GetRowSpan(_draggedContainer);
var targetColumn = Grid.GetColumn(target);
var targetRow = Grid.GetRow(target);
var targetColumnSpan = Grid.GetColumnSpan(target);
var targetRowSpan = Grid.GetRowSpan(target);
if (copyColumn)
{
Grid.SetColumn(_draggedContainer, targetColumn);
}
if (copyRow)
{
Grid.SetRow(_draggedContainer, targetRow);
}
if (copyColumnSpan)
{
Grid.SetColumnSpan(_draggedContainer, targetColumnSpan);
}
if (copyRowSpan)
{
Grid.SetRowSpan(_draggedContainer, targetRowSpan);
}
if (copyColumn)
{
Grid.SetColumn(target, sourceColumn);
}
if (copyRow)
{
Grid.SetRow(target, sourceRow);
}
if (copyColumnSpan)
{
Grid.SetColumnSpan(target, sourceColumnSpan);
}
if (copyRowSpan)
{
Grid.SetRowSpan(target, sourceRowSpan);
}
}
}
private void Released()
{
if (_enableDrag)
{
if (_parent is not null && _draggedContainer is not null)
{
// RemoveAdorner(_draggedContainer);
}
if (_draggedContainer is not null)
{
SetDraggingPseudoClasses(_draggedContainer, false);
}
_enableDrag = false;
_parent = null;
_draggedContainer = null;
}
}
private void SetDraggingPseudoClasses(Control control, bool isDragging)
{
if (isDragging)
{
((IPseudoClasses)control.Classes).Add(":dragging");
}
else
{
((IPseudoClasses)control.Classes).Remove(":dragging");
}
}
}