Получение перетаскивания в MonoMac NSView?

Это мой первый пост здесь, на этом приветственном сайте. Я опытный пользователь С#, .Net и Mono, но Noob в MonoMac, я пытаюсь написать приложение, которое получает папку в 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, но я понятия не имею, что передать массиву строк в качестве типа!

Пожалуйста, помогите мне разобраться. Я искал Google для 48 сейчас!


person Rojan Gh.    schedule 12.03.2012    source источник


Ответы (2)


Наконец-то я сам нашел ответ на свой вопрос, проведя несколько тестов и сравнив их с документами 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;
        }
    }
}

Вот небольшое пояснение:

Сначала я понял, что экземпляр класса Custom создается с помощью Handle, поэтому мне нужно было зарегистрировать RegisterForDraggedTypes в этом методе. Затем я использовал образец документа Apple, чтобы отследить константу строки RegisterForDraggedTypes и извлечь из нее «RegisterForDraggedTypes», чтобы использовать ее в качестве регистрационного значения для пути к файлам. И, используя образец документа Apple, понял, что нужно экспортировать только два метода: draggingEntered: и PerformDragOperation:, поэтому я просто экспортировал их и сам вернул ожидаемые значения вместо обмена сообщениями с Cocoa, чтобы вернуть значение, и теперь все работает нормально . UTI, необходимый для извлечения URL-адресов файлов из NSPasteboardItems, — это UTI Apple, определенный как «public.file-url», поэтому я использовал его для получения путей в виде:

file://localhost/PathToFileOrFolder/FileOrFolderName[/ если это папка]

Надеюсь, это поможет кому-то еще.

Обновление (30 сентября 2015 г.):

Я применил изменения, упомянутые @M_K, к своему коду.

person Rojan Gh.    schedule 14.03.2012

Я заметил, что в последней версии 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;
person M_K    schedule 23.09.2015
comment
не работает, даже если URL-адрес возвращается в виде строки, имеет формат file:///.file/id=. - person Erik Aigner; 28.09.2019