123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- using System;
- using System.Threading.Tasks;
- using Avalonia.Controls;
- using Avalonia.Input;
- using Avalonia.Interactivity;
- using Avalonia.LogicalTree;
- using Avalonia.Xaml.Interactivity;
- namespace Avalonia.Xaml.Interactions.DragAndDrop;
- /// <summary>
- ///
- /// </summary>
- public class ContextDragBehavior : StyledElementBehavior<Control>
- {
- private Point _dragStartPoint;
- private PointerEventArgs? _triggerEvent;
- private bool _lock;
- private bool _captured;
- /// <summary>
- ///
- /// </summary>
- public static readonly StyledProperty<object?> ContextProperty =
- AvaloniaProperty.Register<ContextDragBehavior, object?>(nameof(Context));
- /// <summary>
- ///
- /// </summary>
- public static readonly StyledProperty<IDragHandler?> HandlerProperty =
- AvaloniaProperty.Register<ContextDragBehavior, IDragHandler?>(nameof(Handler));
- /// <summary>
- ///
- /// </summary>
- public static readonly StyledProperty<double> HorizontalDragThresholdProperty =
- AvaloniaProperty.Register<ContextDragBehavior, double>(nameof(HorizontalDragThreshold), 3);
- /// <summary>
- ///
- /// </summary>
- public static readonly StyledProperty<double> VerticalDragThresholdProperty =
- AvaloniaProperty.Register<ContextDragBehavior, double>(nameof(VerticalDragThreshold), 3);
- /// <summary>
- ///
- /// </summary>
- public object? Context
- {
- get => GetValue(ContextProperty);
- set => SetValue(ContextProperty, value);
- }
- /// <summary>
- ///
- /// </summary>
- public IDragHandler? Handler
- {
- get => GetValue(HandlerProperty);
- set => SetValue(HandlerProperty, value);
- }
- /// <summary>
- ///
- /// </summary>
- public double HorizontalDragThreshold
- {
- get => GetValue(HorizontalDragThresholdProperty);
- set => SetValue(HorizontalDragThresholdProperty, value);
- }
- /// <summary>
- ///
- /// </summary>
- public double VerticalDragThreshold
- {
- get => GetValue(VerticalDragThresholdProperty);
- set => SetValue(VerticalDragThresholdProperty, value);
- }
- /// <inheritdoc />
- protected override void OnAttachedToVisualTree()
- {
- AssociatedObject?.AddHandler(InputElement.PointerPressedEvent, AssociatedObject_PointerPressed, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
- AssociatedObject?.AddHandler(InputElement.PointerReleasedEvent, AssociatedObject_PointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
- AssociatedObject?.AddHandler(InputElement.PointerMovedEvent, AssociatedObject_PointerMoved, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
- AssociatedObject?.AddHandler(InputElement.PointerCaptureLostEvent, AssociatedObject_CaptureLost, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
- }
- /// <inheritdoc />
- protected override void OnDetachedFromVisualTree()
- {
- AssociatedObject?.RemoveHandler(InputElement.PointerPressedEvent, AssociatedObject_PointerPressed);
- AssociatedObject?.RemoveHandler(InputElement.PointerReleasedEvent, AssociatedObject_PointerReleased);
- AssociatedObject?.RemoveHandler(InputElement.PointerMovedEvent, AssociatedObject_PointerMoved);
- AssociatedObject?.RemoveHandler(InputElement.PointerCaptureLostEvent, AssociatedObject_CaptureLost);
- }
- private async Task DoDragDrop(PointerEventArgs triggerEvent, object? value)
- {
- var data = new DataObject();
- data.Set(ContextDropBehavior.DataFormat, value!);
- var effect = DragDropEffects.None;
- if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Alt))
- {
- effect |= DragDropEffects.Link;
- }
- else if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Shift))
- {
- effect |= DragDropEffects.Move;
- }
- else if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Control))
- {
- effect |= DragDropEffects.Copy;
- }
- else
- {
- effect |= DragDropEffects.Move;
- }
- await DragDrop.DoDragDrop(triggerEvent, data, effect);
- }
- private void Released()
- {
- _triggerEvent = null;
- _lock = false;
- }
- private void AssociatedObject_PointerPressed(object? sender, PointerPressedEventArgs e)
- {
- var properties = e.GetCurrentPoint(AssociatedObject).Properties;
- if (properties.IsLeftButtonPressed)
- {
- if (e.Source is Control control
- && AssociatedObject?.DataContext == control.DataContext)
- {
- if ((control as ISelectable ?? control.Parent as ISelectable ?? control.FindLogicalAncestorOfType<ISelectable>())?.IsSelected ?? false) e.Handled = true; //avoid deselection on drag
- _dragStartPoint = e.GetPosition(null);
- _triggerEvent = e;
- _lock = true;
- _captured = true;
- }
- }
- }
- private void AssociatedObject_PointerReleased(object? sender, PointerReleasedEventArgs e)
- {
- if (_captured)
- {
- if (e.InitialPressMouseButton == MouseButton.Left && _triggerEvent is not null)
- {
- Released();
- }
- _captured = false;
- }
- }
- private async void AssociatedObject_PointerMoved(object? sender, PointerEventArgs e)
- {
- var properties = e.GetCurrentPoint(AssociatedObject).Properties;
- if (_captured
- && properties.IsLeftButtonPressed &&
- _triggerEvent is not null)
- {
- var point = e.GetPosition(null);
- var diff = _dragStartPoint - point;
- var horizontalDragThreshold = HorizontalDragThreshold;
- var verticalDragThreshold = VerticalDragThreshold;
- if (Math.Abs(diff.X) > horizontalDragThreshold || Math.Abs(diff.Y) > verticalDragThreshold)
- {
- if (_lock)
- {
- _lock = false;
- }
- else
- {
- return;
- }
- var context = Context ?? AssociatedObject?.DataContext;
-
- Handler?.BeforeDragDrop(sender, _triggerEvent, context);
- await DoDragDrop(_triggerEvent, context);
- Handler?.AfterDragDrop(sender, _triggerEvent, context);
- _triggerEvent = null;
- }
- }
- }
- private void AssociatedObject_CaptureLost(object? sender, PointerCaptureLostEventArgs e)
- {
- Released();
- _captured = false;
- }
- }
|