AvaloniaNativeDragSource.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading.Tasks;
  4. using Avalonia.Controls;
  5. using Avalonia.Input;
  6. using Avalonia.Input.Platform;
  7. using Avalonia.Interactivity;
  8. using Avalonia.Native.Interop;
  9. using Avalonia.VisualTree;
  10. namespace Avalonia.Native
  11. {
  12. class AvaloniaNativeDragSource : IPlatformDragSource
  13. {
  14. private readonly IAvaloniaNativeFactory _factory;
  15. public AvaloniaNativeDragSource(IAvaloniaNativeFactory factory)
  16. {
  17. _factory = factory;
  18. }
  19. private static TopLevel FindRoot(object? element)
  20. {
  21. while (element is Interactive interactive && element is not Visual)
  22. element = interactive.GetInteractiveParent();
  23. if (element == null)
  24. return null;
  25. var visual = (Visual)element;
  26. return visual.GetVisualRoot() as TopLevel;
  27. }
  28. class DndCallback : NativeCallbackBase, IAvnDndResultCallback
  29. {
  30. private TaskCompletionSource<DragDropEffects> _tcs;
  31. public DndCallback(TaskCompletionSource<DragDropEffects> tcs)
  32. {
  33. _tcs = tcs;
  34. }
  35. public void OnDragAndDropComplete(AvnDragDropEffects effect)
  36. {
  37. _tcs?.TrySetResult((DragDropEffects)effect);
  38. _tcs = null;
  39. }
  40. }
  41. public Task<DragDropEffects> DoDragDrop(PointerEventArgs triggerEvent, IDataObject data, DragDropEffects allowedEffects)
  42. {
  43. // Sanity check
  44. var tl = FindRoot(triggerEvent.Source);
  45. var view = tl?.PlatformImpl as WindowBaseImpl;
  46. if (view == null)
  47. throw new ArgumentException();
  48. triggerEvent.Pointer.Capture(null);
  49. var tcs = new TaskCompletionSource<DragDropEffects>();
  50. var clipboardImpl = _factory.CreateDndClipboard();
  51. using (var clipboard = new ClipboardImpl(clipboardImpl))
  52. using (var cb = new DndCallback(tcs))
  53. {
  54. if (data.Contains(DataFormats.Text))
  55. // API is synchronous, so it's OK
  56. clipboard.SetTextAsync(data.GetText()).Wait();
  57. view.BeginDraggingSession((AvnDragDropEffects)allowedEffects,
  58. triggerEvent.GetPosition(tl).ToAvnPoint(), clipboardImpl, cb,
  59. GCHandle.ToIntPtr(GCHandle.Alloc(data)));
  60. }
  61. return tcs.Task;
  62. }
  63. }
  64. }