Getting drag and drop in MonoMac NSView?

This is my first post here on this welcome site. I am an experienced C #, Net and Mono user, but Noob in MonoMac, I am trying to write an application that receives a folder in NSView and uses its path to work with files inside the folder ...

The MonoMac framework did not implement draggingEntered:, draggingUpdated:, draggingExited:, prepareForDragOperation:, performDragOperation:, concludeDragOperation: and draggingEnded:

So I tried to implement them myself:

 [Register("TargetView")] public class TargetView:NSView { private static IntPtr selDraggingEntered = Selector.GetHandle ("draggingEntered:"); private static IntPtr selDraggingUpdated = Selector.GetHandle ("draggingUpdated:"); private static IntPtr selDraggingExited = Selector.GetHandle ("draggingExited:"); private static IntPtr selPrepareForDragOperation = Selector.GetHandle ("prepareForDragOperation:"); private static IntPtr selPerformDragOperation = Selector.GetHandle ("performDragOperation:"); private static IntPtr selConcludeDragOperation = Selector.GetHandle ("concludeDragOperation:"); private static IntPtr selDraggingEnded = Selector.GetHandle ("draggingEnded:"); public TargetView():base(){ } public TargetView(NSCoder coder):base(coder){ } public TargetView(NSObjectFlag t):base(t){ } public TargetView(IntPtr handle):base(handle){ } public TargetView(RectangleF frameRect):base(frameRect){ } [Export ("draggingEntered:")] public virtual NSDragOperation DraggingEntered (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { return (NSDragOperation)Messaging.int_objc_msgSend_int (base.Handle, TargetView.selDraggingEntered, (int)sender.DraggingSourceOperationMask); } return (NSDragOperation)Messaging.int_objc_msgSendSuper_int (base.Handle, TargetView.selDraggingEntered, (int)sender.DraggingSourceOperationMask); } [Export ("draggingUpdated:")] public virtual NSDragOperation DraggingUpdated (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { return (NSDragOperation)Messaging.int_objc_msgSend_int (base.Handle, TargetView.selDraggingUpdated, (int)sender.DraggingSourceOperationMask); } return (NSDragOperation)Messaging.int_objc_msgSendSuper_int (base.Handle, TargetView.selDraggingUpdated, (int)sender.DraggingSourceOperationMask); } [Export ("draggingExited:")] public virtual void DraggingExited (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { Messaging.void_objc_msgSend_int (base.Handle, TargetView.selDraggingExited, (int)sender.DraggingSourceOperationMask); } Messaging.void_objc_msgSendSuper_int (base.Handle, TargetView.selDraggingExited, (int)sender.DraggingSourceOperationMask); } [Export ("prepareForDragOperation:")] public virtual bool PrepareForDragOperation (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { return Messaging.bool_objc_msgSend_int (base.Handle, TargetView.selPrepareForDragOperation, (int)sender.DraggingSourceOperationMask); } return Messaging.bool_objc_msgSendSuper_int (base.Handle, TargetView.selPrepareForDragOperation, (int)sender.DraggingSourceOperationMask); } [Export ("performDragOperation:")] public virtual bool PerformDragOperation (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { return Messaging.bool_objc_msgSend_int (base.Handle, TargetView.selPerformDragOperation, (int)sender.DraggingSourceOperationMask); } return Messaging.bool_objc_msgSendSuper_int (base.Handle, TargetView.selPerformDragOperation, (int)sender.DraggingSourceOperationMask); } [Export ("concludeDragOperation:")] public virtual void ConcludeDragOperation (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { Messaging.void_objc_msgSend_int (base.Handle, TargetView.selConcludeDragOperation, (int)sender.DraggingSourceOperationMask); } Messaging.void_objc_msgSendSuper_int (base.Handle, TargetView.selConcludeDragOperation, (int)sender.DraggingSourceOperationMask); } [Export ("draggingEnded:")] public virtual void DraggingEnded (NSDraggingInfo sender) { if (sender == null) { throw new ArgumentNullException ("sender"); } if (this.IsDirectBinding) { Messaging.void_objc_msgSend_int (base.Handle, TargetView.selDraggingEnded, (int)sender.DraggingSourceOperationMask); } Messaging.void_objc_msgSendSuper_int (base.Handle, TargetView.selDraggingEnded, (int)sender.DraggingSourceOperationMask); } } 

But methods are not called!

I also tried RegisterForDraggedTypes , but I have no idea what to pass to a string array as a type!

Please help me sort it out. I searched google for 48 now!

+4
source share
2 answers

I finally found the answer to my question by running some tests and comparing them with Apple docs in drag and drop sessions.

Here is the source I used, and this is the world like a charm:

 [Register("DropTargetView")] public class DropTargetView:NSView { public DropTargetView(IntPtr handle):base(handle){ RegisterForDraggedTypes(new string[]{"NSFilenamesPboardType"}); } [Export ("draggingEntered:")] public NSDragOperation DraggingEntered (NSDraggingInfo sender) { NSPasteboard pasteboard = sender.DraggingPasteboard; bool typeExists = (Array.IndexOf(pasteboard.Types,"NSFilenamesPboardType") >= 0); if(typeExists) { return NSDragOperation.Link; } else { return NSDragOperation.None; } } [Export ("performDragOperation:")] public bool PerformDragOperation (NSDraggingInfo sender) { NSPasteboard pasteboard = sender.DraggingPasteboard; bool typeExists = (Array.IndexOf(pasteboard.Types,"NSFilenamesPboardType") >= 0); if(typeExists) { NSPasteboardItem[] pasteboardItems = pasteboard.PasteboardItems; for(int i = 0; i < pasteboardItems.Length; i++) { string urlStr = pasteboardItems[i].GetStringForType("public.file-url"); NSUrl url = new NSUrl (urlStr); string filePath = url.Path; Console.WriteLine(filePath); } return true; } else { return false; } } } 

Here is a little explanation:

At first I found out that the user class is created using Handle, so I need to register RegisterForDraggedTypes in this method. Then I used a sample Apple document to trace the line Const RegisterReportDraggedTypes and deduce "RegisterForDraggedTypes" from it to use it as a registration value for the file path. And using a sample Apple document showed that only two methods that need to be exported are draggingEntered: and performDragOperation :, so I just exported them and returned the expected values โ€‹โ€‹myself instead of Cocoa messages to return the value, and everything works fine now. The UTI needed for the URLs of files to be extracted from NSPasteboardItems is the Apple UTI, defined as "public.file-url", so I used it to get the paths in the form:

file: // localhost / PathToFileOrFolder / FileOrFolderName [/ if this is a folder]

Hope this helps someone else.

Update (2015-09-30):

I applied the changes mentioned by @M_K to my code.

+7
source

I noticed that with the latest version of MonoMac / Xamarin, calling pasteboardItems[i].GetStringForType("public.file-url") returns the URL instead of the file path:

File:. File //// ID = ...

To get the file path you need to do this:

 string urlStr = pasteboardItems[i].GetStringForType("public.file-url"); NSUrl url = new NSUrl (urlStr); string filePath = url.Path; 
0
source

Source: https://habr.com/ru/post/1401071/


All Articles