DragDrop between 2 instances of same VB.Net program doesn't work

J

JohnR

I am using dragdrop to drag and drop a custom class instance. When I
drag/drop from one window to another window in the same application
everything works fine. But when trying to move between the same windows
running in different instances of the application the "dropped" data comes
across as a system.__ComObject and I can't CType it to my class to extract
the data. I've been searching for hours and haven't found any solution so
I am hoping that somebody can help me out here. Has anybody who has done
this in VB.Net please share the solution.

Thanks, John
 
B

Bart Mermuys

Hi,

JohnR said:
I am using dragdrop to drag and drop a custom class instance. When I
drag/drop from one window to another window in the same application
everything works fine. But when trying to move between the same windows
running in different instances of the application the "dropped" data comes
across as a system.__ComObject and I can't CType it to my class to extract
the data. I've been searching for hours and haven't found any solution so
I am hoping that somebody can help me out here. Has anybody who has done
this in VB.Net please share the solution.

Have you tried using the Serializable attribute on your custom class ?

<Serializable()> _
Public Class CustomClass
' If this class references an other class then that other
' class must also have the Serializable attribute or the
' field that references the other class must have the
' NonSerialized attribute.
End Class

Public Sub DragDrop( .....)
Dim co As CustomClass
co = DirectCast( _
e.Data.GetData(GetType(CustomClass)), _
CustomClass )

End Sub

HTH,
Greetings
 
J

JohnR

Hi Bart,

I put the <serializable()> attribute on my custom class and I'm getting a
little closer :). Now what is happening is that the "dragdrop" doesn't
seem to be able to access what I am dragging. Using a breakpoint in my
dragdrop routine and using quickview the 'structures' in my custom class
come across (ie: the arraylist is an arraylist) but the contents of the
arraylist is "System.runtime.remoting.proxies.__TransparentProxy" and I
can't seem to get to my data.

Any Ideas of how I might do this?

Thanks, John
 
B

Bart Mermuys

Hi,

JohnR said:
Hi Bart,

I put the <serializable()> attribute on my custom class and I'm getting
a little closer :). Now what is happening is that the "dragdrop" doesn't
seem to be able to access what I am dragging. Using a breakpoint in my
dragdrop routine and using quickview the 'structures' in my custom class
come across (ie: the arraylist is an arraylist) but the contents of the
arraylist is "System.runtime.remoting.proxies.__TransparentProxy" and I
can't seem to get to my data.

If the content is __TransparentProxy then the object in the ArrayList
inherits from MarshalByRefObject, doesn't need to be directly.

If you pass data from one app to another then it can't be accessed directly
because each app has it own memory space.

So the objects needs to be copied ( serializable ) or they need to be
accessed through Remoting (MarshalByRefObject). If you access them through
Remoting then you use a proxy object that is connected to the real object,
and you can cast this __TransparentProxy to your original class.

To keep it simple, try to keep the object graph copyable, meaning all
objects have the Serializable attribute and don't inherit from
MarshalByRefObject directly or indirectly.

If you still want to use MarshalByRefObject's (and therefore Remoting) then
you have to register a Channel, i'm no expert at remoting, but it should
look like:

' set a reference to System.Runtime.Remoting.dll at project references
' then use this code
Import System.Runtime.Remoting.Channels
Import System.Runtime.Remoting.Channels.Tcp

Public Sub Form_Load(...) Handles Form.Load
Dim ch As New TcpChannel(0)
ChannelServices.RegisterChannel(ch)
End Sub

HTH,
Greetings
 
J

JohnR

Hi Bart,



First I want to thank you for taking the time to help me out... I really
appreciate it.



I certainly don't want to use MarshalByRefObject's. I really want to keep
it as simple as possible. As I mentioned the drag/drop works fine within
different windows in the same program, and I'm trying to make it work when
doing a drag/drop from the 'same' windows in different instances of the
program. I don't think I am using anything that is not serializable. Here
is my class that I am attempting to drag/drop (the ultragrid is a grid
control from Infergistics (an excellent set of controls, by the way)):



#Region "MyDragDropContainer class"

<Serializable()> _

Public Class MyDragDropContainer

Private _SelectedRows As New ArrayList

Private _SelectedCells As New ArrayList

Private _SourceGrid As UltraGrid



Property SourceGrid() As UltraGrid

Get

Return _SourceGrid

End Get

Set(ByVal Value As UltraGrid)

_SourceGrid = Value

End Set

End Property



Public Property SelectedCells() As ArrayList

Get

Return _SelectedCells

End Get

Set(ByVal Value As ArrayList)

_SelectedCells = Value

End Set

End Property



Public Property SelectedRows() As ArrayList

Get

Return _SelectedRows

End Get

Set(ByVal Value As ArrayList)

_SelectedRows = Value

End Set

End Property

End Class

#End Region



this is how I load the instance of the class



Public Function LoadDragDropContainer(ByRef MyGrid As UltraGrid) As
MyDragDropContainer

Dim ddc As New MyDragDropContainer

Dim myRow As UltraGridRow

Dim myCell As UltraGridCell

For Each myRow In MyGrid.Selected.Rows

ddc.SelectedRows.Add(myRow)

Next

For Each myCell In MyGrid.Selected.Cells

ddc.SelectedCells.Add(myCell)

Next

ddc.SourceGrid = MyGrid

Return ddc



End Function



And then I do the "DoDragDrop" filling the dataobject with 2 sets of data.
one is my custom class, and the other is a plain string so I can drop to an
entity that will accept strings.



ddc = LoadDragDropContainer(CType(sender, UltraGrid)) 'sender is my grid
passed to the mousemove event

data_object.SetData("MyDragDropContainer", False, ddc)

data_object.SetData(DataFormats.StringFormat, True,
myCell.Row.Cells("MyField").Text)

ug.DoDragDrop(data_object, DragDropEffects.Copy)



Do you see anything that might be causing a problem or causing
MarshalByRefObjects to be invoked???





Thanks, John
 
B

Bart Mermuys

Hi,

JohnR said:
Hi Bart,



First I want to thank you for taking the time to help me out... I really
appreciate it.



I certainly don't want to use MarshalByRefObject's. I really want to keep
it as simple as possible. As I mentioned the drag/drop works fine within
different windows in the same program,

Yes, but I explained that it is much harder between apps, because of the
seperated memory space or different AppDomains in .NET.
and I'm trying to make it work when doing a drag/drop from the 'same'
windows in different instances of the program. I don't think I am using
anything that is not serializable.

Because of the __TransparentProxy I'm suspecting that that object inherits
(direct or indirectly) from MarshalByRefObject.
Here is my class that I am attempting to drag/drop (the ultragrid is a
grid control from Infergistics (an excellent set of controls, by the
way)):
Do you see anything that might be causing a problem or causing
MarshalByRefObjects to be invoked???

Unfortunately it is impossible for me to see this without having the
UltraGrid. You should check if UltraGrid, UltraGridCell and UltraGridRow
inherit directly or indirectly from MarshalByRefObject, you can see this
inside the Object Browser (visual studio) or in the documentation for the
grid.

I'm almost certain UltraGrid inherits indirectly from MarshalByRefObject
because if it inherits from Control, then
UltraGrid -> Control -> Component -> MarshalByRefObject.


HTH,
Greetings
 
J

JohnR

Hi Bart,

You are certainly correct. The Infergistics grid stuff all inherits from
MarshalbyRefObject. While researching this topic, I have found statements
such as ".NET allows you to MarshalByRef or MarshalByValue" , so the next
logical question is when I'm loading the instance of my custom class with
the ultragrid stuff, can I force it to MarshalByValue?????

John
 
B

Bart Mermuys

Hi,

JohnR said:
Hi Bart,

You are certainly correct. The Infergistics grid stuff all inherits
from MarshalbyRefObject. While researching this topic, I have found
statements such as ".NET allows you to MarshalByRef or MarshalByValue" ,
so the next logical question is when I'm loading the instance of my custom
class with the ultragrid stuff, can I force it to MarshalByValue?????

If all classes involved have the Serializable attribute, then you can force
marshal by value by serializing everthing into a MemoryStream and then pass
a Byte array between apps and then deserialize the Byte array. But i doubt
that will work, because eg. Control class is not marked Serializable. And
even if it would, it makes not much sense to copy a Control because it is on
a Form. It may work for the cells or rows alone but that also depends if
they are marked Serializable.

I think the best thing you can do is either use remoting ( adding a
Channel ) or extract the values you need and put them in serializable
classes that don't inherit from MarshalByRefObject.

HTH,
Greetings

Code to force marshal-by-value:

Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO

Public Sub MouseDown( .. ) Handles SomeControl.MouseDown
Dim bf As New BinaryFormatter
Dm ms As New MemoryStream
Dim data As New DataObject
Dim co As New MyDragDropContainer
...
bf.Serialize( ms, co )
data.SetData( "MyDragDropContainer", False, ms.ToArray() )
SomeControl.DoDragDrop( data, .... )

End Sub

Public Sub DragDrop(...) Handles SomeControl.DragDrop
Dim bf As New BinaryFormatter
Dm ms As New MemoryStream( _
DirectCast( e.Data.GetData("MyDragDropContainer"), Byte() )

Dim co As MyDragDropContainer = _
DirectCast( bf.Deserialize( ms ), MyDragDropContainer )

End Sub

HTH,
Greetings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top