在MonoMac NSView中接收拖放?

时间:2012-03-12 23:42:15

标签: cocoa drag-and-drop nsview monomac

这是我在这个问候网站上发表的第一篇文章。 我是一名经验丰富的C#,。Net和Mono用户,但MonoMac中的Noob, 我正在尝试编写一个在NSView上接收文件夹的应用程序,并使用其路径对文件夹中的文件执行操作...

MonoMac框架未实现draggingEntered:, draggingUpdated:, draggingExited:, prepareForDragOperation:, performDragOperation:, concludeDragOperation: and draggingEnded:

所以我试着自己实现它们:

[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);
    }
}

但这些方法没有被调用!

我也试过RegisterForDraggedTypes但是我不知道要把什么传递给字符串数组作为类型!

请帮我搞清楚。我一直在谷歌搜索48!

2 个答案:

答案 0 :(得分:7)

我终于通过做一些测试并将它们与拖放会话中的Apple文档进行比较,找到了我自己问题的答案。

以下是我使用的来源,它的世界就像一个魅力:

[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;
        }
    }
}

这是一个小解释:

我首先想到使用Handle实例化Custom类,所以我需要在该方法中注册RegisterForDraggedTypes。 然后我使用Apple的文档示例跟踪RegisterForDraggedTypes字符串const并从中取出“RegisterForDraggedTypes”,将其用作文件路径的注册值。 使用Apple的文档示例表明需要导出的只有两种方法是draggingEntered:和performDragOperation:所以我只是导出它们并自己返回预期值而不是传递Cocoa来返回值,一切正常。 从NSPasteboardItems中提取文件URL所需的UTI是UTI Apple定义为“public.file-url”,因此我使用它来获取以下形式的路径:

  

file:// localhost / PathToFileOrFolder / FileOrFolderName [/如果是   文件夹]

希望它可以帮助别人。

更新(2015-09-30):

我已将@M_K提到的更改应用于我的代码。

答案 1 :(得分:0)

我注意到使用最新版本的MonoMac / Xamarin,调用pasteboardItems[i].GetStringForType("public.file-url")而不是文件路径,它会返回一个URL:

  

文件:///文件/ ID = ...

要获取文件路径,您需要执行此操作:

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