DragDrop of Files

Zenerdiode

Active Member
Licensed User
I'd like to implement Drag & Drop of files from Explorer to a Multiline TextBox on my form. The DragDrop Event should then fire to grab the FilePath of the file dropped and open it.

But I'm falling at the first hurdle. I'm getting an error of 'The given key was not present in the dictionary'. This is caused by the DragDrop key. Other TextBox event types work fine in there, such as Click.

Many Thanks.
 

Attachments

Cableguy

Expert
Licensed User
According to the error message, the method or event is not implemented in the view you are using it with
 

Zenerdiode

Active Member
Licensed User
Hello Paulo,

Long time since I was last here; good to hear from you. I'm puzzled, as the TextBox does support Drag & Drop, I'm just wondering if the Basic4PPC TextBox is a modified control by Erel - and not a native one.
 

Cableguy

Expert
Licensed User
Hello Paulo,

Long time since I was last here; good to hear from you. I'm puzzled, as the TextBox does support Drag & Drop, I'm just wondering if the Basic4PPC TextBox is a modified control by Erel - and not a native one.
Long time no read!

I believe you are correct about it being a downsized control... I would suggest either trying using the door lib or, since DLL creating is quite easy with c# and sharp develop, create your own custom control.
 

agraham

Expert
Licensed User
I don't know why you are getting an error as your code is actually correct. The Basic4ppc TextBox is a standard TextBox and will work as such. In your code the Enter event is being fired but the problem is that you need to tell the souce of the drag that you can accept the data. This is done by examining the Data property of the DragEventArgs to see if it is the type of data that you can accept and if so set the Effect property of DragEventArgs with one or more DragDropEffect flags that the drag source will accept. In this case DragDropEffects.Copy should work. Only if you do this will the cursor change and the Drop event be fired. This should all be possible using Door library Objects but it is non-trivial as Drag and Drop is based on the Clipboard data formats which in turn is based on COM and not .NET so it can seem a bit convoluted in the .NET world.

Unfortunately I don't have any code already written for this so you will need to read up on Drag and Drop and do some experimenting.
 

agraham

Expert
Licensed User
This works for me but I am using my own Reflection library that is a superset of DoorEx but I think it will work with the Door or DoorEx libraries.

I haven't posted it as a project as version 6.90 of Basic4ppc would not load it (my personal version is up to 8.00 now! :)) but it should paste into your existing project but will need an ObjectArray or ObjectArrayEx object added.

There is no data format checking done here as I kept it as simple as possible so you may get odd errors if you drag odd things into the TextBox

B4X:
Sub Globals
    'Declare the global variables here.
    Dim DataFormats(0) AsString
End Sub

Sub App_Start
   Obj1.New1
   Obj1.FromControl("TextBox1")
   Obj1.SetProperty("AllowDrop","True")
   Enter.New1(Obj1.Value,"DragEnter")
   Drop.New1(Obj1.Value,"DragDrop")
   Form1.Show
End Sub

Sub Enter_NewEvent
   Obj1.Value = Enter.Data
   Obj1.Value = Obj1.GetProperty("Data")
   ' this block of code might work (or not) for you in the IDE but won't compile
   ' DataFormats() = Obj1.RunMethod("GetFormats") ' COM not .NET names of formats
   ' For i = 0 To ArrayLen(DataFormats()) -1
   ' msg = msg & DataFormats(i) & CRLF
   ' Next
   ' Msgbox(msg, ArrayLen(DataFormats()))
   Obj1.Value = Enter.Data
   Obj1.SetProperty("Effect", "Copy" )
End Sub

Sub Drop_NewEvent
   Obj1.Value = Drop.Data
   Obj1.Value = Obj1.GetProperty("Data")
   ObjArray1.New1(0)
   ObjArray1.Value = Obj1.RunMethod2("GetData", "FileNameW", "System.String")
   data = ObjArray1.Get(0)
   Msgbox(data)
End Sub
 

agraham

Expert
Licensed User
I've installed 6.90 and see the "key not present error". This is because the Door library can only handle a few types of EventHandler.

In this archive is a 6.90 project using my Reflection library which will cope with any type of EventHandler. Drag and Drop will only work when compiled under 6.90. For some reason the Enter_NewEvent event is not raised in the 6.90 IDE whereas it is in my version of the IDE. I can't remember what I changed that might cause this.
 

Attachments

agraham

Expert
Licensed User
Basic4ppc, including 6.90, could not pass internal data to a library method with an Object type parameter. It was because of this that the Door and DoorEx libraries had two variants of, say SetProperty, one taking a String as the value parameter and the other taking an Object. The first was used to set data from within Basic4ppc and the other to set "real" Objects from an external library.

I have changed my own version of Basic4ppc to be able to pass to internal data as String types to Object parameters which let me rewrite the DoorEx library as my new Reflection library and remove the String based duplicated methods. However this means that your Basic4ppc cannot use SetProperty in this library as (despite what the Reflection help might still say) it takes Object type parameters, as do the RunMethod variants.

The workaround is to use Object.ValueAsString to set the Value of a Reflection Object to the required value as a string and then pass that Value as the value parameter of a Reflection library method. This works for numbers, strings, Booleans and enum names.

So for your drag and drop this doesn't work passing a String to an Object parameter from inside Basic4pp with the Reflection library.
B4X:
    Obj1.New1
    Obj1.FromControl("TextBox1")
    Obj1.SetProperty("AllowDrop","True")
Using an intermediate Object does work as the String being passed to an Object parameter is now from outside Basic4ppc which does work.
B4X:
    Obj1.New1
    Obj1.FromControl("TextBox1")
    Obj2.New1
    Obj2.ValueAsString = "True"
    Obj1.SetProperty("AllowDrop",Obj2.Value)
Attached is a 6.90 project that should work in the IDE as well as when compiled.
 

Attachments

Zenerdiode

Active Member
Licensed User
Thank You very much indeed Andrew, does exactly what I want and need. I didn't have a copy of your Reflecton library; but I see you've kindly included one.

Best-
Christopher
 

agraham

Expert
Licensed User
By using "FileDrop" instead of "FileNameW" you can accept a selection of more than one file.
B4X:
Sub Drop_NewEvent
    Obj1.Value = Drop.Data
    Obj1.Value = Obj1.GetProperty("Data")
    ObjArray1.New1(0)
    Obj2.New1
    Obj2.ValueAsString = "FileDrop"   
ErrorLabel(Error)
    ObjArray1.Value = Obj1.RunMethod2("GetData", Obj2.Value, "System.String")
    Obj1.Value = ObjArray1.Value
    l = Obj1.GetProperty("Length")
    For i = 0 To l - 1
        data = data & ObjArray1.Get(i) & CRLF
    Next
    TextBox1.Text = data
    Return
Error:
    Msgbox("Invalid filename")
End Sub
 

Zenerdiode

Active Member
Licensed User
You're now answering questions before I've even asked:)
I was wondering about multiple files, together with how to get the size of the ObjectArray with there being no 'ObjArray.Arraylen' property.

I did try to read up on the subject before posing my question in the first place, but I'm still learning every day. My inspiration was from here:

https://msdn.microsoft.com/en-us/library/aa289508(v=vs.71).aspx

By using "FileDrop" instead of "FileNameW" you can accept a selection of more than one file.
B4X:
Sub Drop_NewEvent
    Obj1.Value = Drop.Data
    Obj1.Value = Obj1.GetProperty("Data")
    ObjArray1.New1(0)
    Obj2.New1
    Obj2.ValueAsString = "FileDrop"  
ErrorLabel(Error)
    ObjArray1.Value = Obj1.RunMethod2("GetData", Obj2.Value, "System.String")
    Obj1.Value = ObjArray1.Value
    l = Obj1.GetProperty("Length")
    For i = 0 To l - 1
        data = data & ObjArray1.Get(i) & CRLF
    Next
    TextBox1.Text = data
    Return
Error:
    Msgbox("Invalid filename")
End Sub
 
Top