Frage

It's my first post here, on this greet website. I'm an experienced C#, .Net and Mono user but Noob in MonoMac, I'm trying to write an App that receives a folder on an NSView and uses its path to do things with the files inside the folder...

The MonoMac framework did not implement the 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 the methods do not get called!

I Also tried to RegisterForDraggedTypes but I have no idea what to pass to the string array as the type!

Please help me figure it out. I have been searching the google for 48 now!

War es hilfreich?

Lösung

I finally found the answer to my question myself by doing some tests and comparing them to the Apple documents on Drag and Drop sessions.

Here is the source I used and it 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:

I first figured out that the Custom class is being instanced using Handle so I needed to register the RegisterForDraggedTypes in that method. Then I used an Apple's document's sample to trace the RegisterForDraggedTypes string const and take the "RegisterForDraggedTypes" out of it to use it as the registering Value for the files' path. And using the Apple's document's sample figured it out that the only 2 methods needed to be exported are draggingEntered: and performDragOperation:, so I just exported them and returned the expected values myself instead of Messaging the Cocoa to return the value and everything works fine now. The UTI needed for the file URLs to be extracted from the NSPasteboardItems is the UTI Apple defined as "public.file-url", so I used it to get the paths in the form of:

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

Hope it helps someone else.

Update (2015-09-30):

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

Andere Tipps

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

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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top