-
Extend Constituent Control Drag Events
I have created a user control with one constituent control: a treeview. I
can drag and drop nodes just fine within the treeview, but once I leave the
bounds of the user control, the mouse icon changes to a no-drop and I can't
raise any dragover or dragdrop events on any other object.
The same treeview works fine if I put it on a form without being contained
in a user control. I can instantiate multiple instances of said form and
drag/drop between the treeviews on the different form instances without any
problem.
How do I extend the treeveiw drag events beyond the bounds of its container?
Incidentally I am controlling drag/drop manually and I am not using OLEDrag.
-
Re: Extend Constituent Control Drag Events
Todd -
We have come up against this problem, and I hope that it isn't too late to
change your design.
Basically, this behaviour, as Microsoft often says, is by design. "Standard
VB" drag drop will only work for controls on a VB container, such as a Form,
UserDocument, UserControl, etc. Another thing you must realise it that
within drag drop, VB only sees the "Extender" object that wraps up each
control - it cannot see "into" the control, because else this would break
COM encapsulation. COM is supposed to be language independent, so we cannot
assume that the code inside the control understands VB drag drop.
So there are two ways that you can solve this problem: one ideal, one hacky.
Guess which one we chose <g>.
The "ideal" way is to use the COM standard way to do drag drop. Since every
language or library implements and interfaces drag drop in different ways,
Microsoft decided to create a standard way to do this - called OLEDragDrop,
in Visual Basic. Luckily, all intrinsic VB controls support this, as do the
Common Controls OCXs supplied by Microsoft. The majority of modern 3rd
party controls do as well, although you ought to check this out to be sure.
Behind the scenes, this magic is enacted by requiring a control to implement
one or more of the COM interfaces, such as IDragDrop. You won't have to
know about these interfaces; however, you ought to know that the mechanism
of drag drop is quite different from the VB drag drop mechanism. The latter
is based around the concept of dragging controls over and onto other
controls. However, OLE drag drop is far more sophisticated, involving a
number of conversations (represented by one of 6 possible events as opposed
to VB's two events) between a data source and a data destination. Data
sources and destinations can supply data in any of a multitude of formats,
which are based on the clipboard formats (and can potentially be extended ad
finitum). More than one data format can be made available, and the
destination can choose one or more of these formats). Many of the VB
controls already have automatic support for particular formats. For
instance, if you set the textbox's OLEDragMode to Automatic, you can select
its text, and drag it. Likewise, a textbox's OLEDropMode at Automatic
allows you to drag text into it, and it is automatically inserted.
Now this is all well and cool, but what is important for you is that OLE
Drag Drop doesn't care about your application's structure. All it knows is
that if you OLE drag something over a window, regardless of its position in
a hierarchy of windows, a conversation will be attempted with that window,
and so you have a chance to drag stuff into it. So set your TreeView
control's OLEDrag to Manual, and get reading the manual!!
Of course, it may be too late for that - you have already written tons of
drag drop code. Even so, consider junking it, because despite your loss,
you will gain a wonderful flexibility. But, just in case, I should tell you
how we got round this: The Mouse_Down and Mouse_Move <within> the
UserControl code gives the signal to start the drag. However, we don't drag
the internal tree. Instead, we raise an event, StartDrag, and in the
external form's event procedure, we do <TreeUserControl1.Drag 1>. Now, all
the drag drop is happening on the form. Whenever the
<TreeUserControl1_DragOver> and <TreeUserControl1_DragDrop> events fire, the
DragOver and DragDrop method that we have created on the UserControl are
called, thus providing us feedback.
Personally, this set-up definitely sucks big time, and the more I think of
it, the more angry I get. If you do it this way, you code becomes very
non-portable. It also only works for one level of drag drop. If, for
instance, you wanted to further encapsulate <TreeUserControl1> into another
UserControl, you would have to write yet more delegation code.
Anyway, I hope that this helps.
--
---------------------------------------
Mark Alexander Bertenshaw
Programmer/Analyst
Prime Response
Brentford
UK
"Todd Mitchell" <Todd.Mitchell@RuckusInteractive.com> wrote in message
news:38e7fd15$1@news.devx.com...
>
> I have created a user control with one constituent control: a treeview. I
> can drag and drop nodes just fine within the treeview, but once I leave
the
> bounds of the user control, the mouse icon changes to a no-drop and I
can't
> raise any dragover or dragdrop events on any other object.
>
> The same treeview works fine if I put it on a form without being contained
> in a user control. I can instantiate multiple instances of said form and
> drag/drop between the treeviews on the different form instances without
any
> problem.
>
> How do I extend the treeveiw drag events beyond the bounds of its
container?
>
> Incidentally I am controlling drag/drop manually and I am not using
OLEDrag.
-
Re: Extend Constituent Control Drag Events
Mark -
Thanks for the response! I sincerely appreciate the time you took to write
this. It is helpful to see how others have tackled these issues.
What I wound up doing was to create a Class Object that wraps up a TreeView
object. I exposed this TreeView object as a property of the Class Object,
and replicated all the TreeView events as methods of the Class Object.
Each form that needs the TreeView sets the Class Object's TreeView object
property equal to the TreeView on the form. By setting the form's TreeView
BYREF equal to the Class Object's TreeView object, anything done to the TreeView
in the Class Object is, naturally, done to the TreeView on the form. (I
actually found a great example of how ByRef should be used!)
This does require you to trap each of the Form TreeView's events and pass
the event arguments directly to the corresponding methods of the Class Object,
like this:
Private Sub tvwExposure_DragDrop(Source As Control, X As Single, Y As Single)
' moTreeview is a module level instance of clsTreeView
moTreeview.ClassTreeview_DragDrop Source, X, Y
End Sub
On the surface, this sounds like a bit of a hack, but it is operating quite
well and the code is pretty easy to read since it is close to what would
otherwise be expected.
I'll keep sloggin' away,
Todd
http://webpages.mr.net/mitcht/
"Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote:
>Todd -
>
>We have come up against this problem, and I hope that it isn't too late
to
>change your design.
>
>Basically, this behaviour, as Microsoft often says, is by design. "Standard
>VB" drag drop will only work for controls on a VB container, such as a Form,
>UserDocument, UserControl, etc. Another thing you must realise it that
>within drag drop, VB only sees the "Extender" object that wraps up each
>control - it cannot see "into" the control, because else this would break
>COM encapsulation. COM is supposed to be language independent, so we cannot
>assume that the code inside the control understands VB drag drop.
>
>So there are two ways that you can solve this problem: one ideal, one hacky.
>Guess which one we chose <g>.
>
>The "ideal" way is to use the COM standard way to do drag drop. Since every
>language or library implements and interfaces drag drop in different ways,
>Microsoft decided to create a standard way to do this - called OLEDragDrop,
>in Visual Basic. Luckily, all intrinsic VB controls support this, as do
the
>Common Controls OCXs supplied by Microsoft. The majority of modern 3rd
>party controls do as well, although you ought to check this out to be sure.
>Behind the scenes, this magic is enacted by requiring a control to implement
>one or more of the COM interfaces, such as IDragDrop. You won't have to
>know about these interfaces; however, you ought to know that the mechanism
>of drag drop is quite different from the VB drag drop mechanism. The latter
>is based around the concept of dragging controls over and onto other
>controls. However, OLE drag drop is far more sophisticated, involving a
>number of conversations (represented by one of 6 possible events as opposed
>to VB's two events) between a data source and a data destination. Data
>sources and destinations can supply data in any of a multitude of formats,
>which are based on the clipboard formats (and can potentially be extended
ad
>finitum). More than one data format can be made available, and the
>destination can choose one or more of these formats). Many of the VB
>controls already have automatic support for particular formats. For
>instance, if you set the textbox's OLEDragMode to Automatic, you can select
>its text, and drag it. Likewise, a textbox's OLEDropMode at Automatic
>allows you to drag text into it, and it is automatically inserted.
>
>Now this is all well and cool, but what is important for you is that OLE
>Drag Drop doesn't care about your application's structure. All it knows
is
>that if you OLE drag something over a window, regardless of its position
in
>a hierarchy of windows, a conversation will be attempted with that window,
>and so you have a chance to drag stuff into it. So set your TreeView
>control's OLEDrag to Manual, and get reading the manual!!
>
>Of course, it may be too late for that - you have already written tons of
>drag drop code. Even so, consider junking it, because despite your loss,
>you will gain a wonderful flexibility. But, just in case, I should tell
you
>how we got round this: The Mouse_Down and Mouse_Move <within> the
>UserControl code gives the signal to start the drag. However, we don't
drag
>the internal tree. Instead, we raise an event, StartDrag, and in the
>external form's event procedure, we do <TreeUserControl1.Drag 1>. Now,
all
>the drag drop is happening on the form. Whenever the
><TreeUserControl1_DragOver> and <TreeUserControl1_DragDrop> events fire,
the
>DragOver and DragDrop method that we have created on the UserControl are
>called, thus providing us feedback.
>
>Personally, this set-up definitely sucks big time, and the more I think
of
>it, the more angry I get. If you do it this way, you code becomes very
>non-portable. It also only works for one level of drag drop. If, for
>instance, you wanted to further encapsulate <TreeUserControl1> into another
>UserControl, you would have to write yet more delegation code.
>
>
>Anyway, I hope that this helps.
>--
>
>---------------------------------------
>Mark Alexander Bertenshaw
>Programmer/Analyst
>Prime Response
>Brentford
>UK
>"Todd Mitchell" <Todd.Mitchell@RuckusInteractive.com> wrote in message
>news:38e7fd15$1@news.devx.com...
>>
>> I have created a user control with one constituent control: a treeview.
I
>> can drag and drop nodes just fine within the treeview, but once I leave
>the
>> bounds of the user control, the mouse icon changes to a no-drop and I
>can't
>> raise any dragover or dragdrop events on any other object.
>>
>> The same treeview works fine if I put it on a form without being contained
>> in a user control. I can instantiate multiple instances of said form
and
>> drag/drop between the treeviews on the different form instances without
>any
>> problem.
>>
>> How do I extend the treeveiw drag events beyond the bounds of its
>container?
>>
>> Incidentally I am controlling drag/drop manually and I am not using
>OLEDrag.
>
>
-
Re: Extend Constituent Control Drag Events
Mark,
There is a far better way to do this that VB 6 (and 5?) has given us. In
your class module, dim the treeview as withevents. eg (at top of class)
Private Withevents mtvwMain as TreeView
Then, as you already had done:
Public Property Set Treeview(ByVal NewVal as TreeView)
set mtvwMain=NewVal
End Property
Now your class will automatically get all treeview events without you writing
any extra code (in fact, you write MUCH less code). Note that mtvwMain is
an item in the top left combo box, and the events are in the combobox on
the right - exactely as they were when you where writing your usercontrol.
You could even do this with a usercontrol, instead of a class, then it could
have persistant properties. Make it windowless and 'invisibleAtRuntime' to
save resources.
Also, make sure you set it to nothing in class_terminate.
Both these methods have an advantage over putting a control on a usercontrol
- they both only use one window handle, were a control on a usercontrol uses
2. This doesn't sound that bad, but make a big form full of these usercontrols
and you will have alot of windows.
Also, passing in the treeview by ref makes no difference. The object (treeview)
sits in memory somewhere. You get a pointer to it. If you pass it in byVal,
you duplicate the pointer. But if you pass it in byRef, you get the same
pointer (or maybe a pointer to the pointer, i'm not sure which). But the
point is (hehe) they all point to the one object in memory, hence all do
the same thing.
Mike
"Todd Mitchell" <Todd.Mitchell@RuckusInteractive.com> wrote:
>
>Mark -
>
>Thanks for the response! I sincerely appreciate the time you took to write
>this. It is helpful to see how others have tackled these issues.
>
>What I wound up doing was to create a Class Object that wraps up a TreeView
>object. I exposed this TreeView object as a property of the Class Object,
>and replicated all the TreeView events as methods of the Class Object.
>
>Each form that needs the TreeView sets the Class Object's TreeView object
>property equal to the TreeView on the form. By setting the form's TreeView
>BYREF equal to the Class Object's TreeView object, anything done to the
TreeView
>in the Class Object is, naturally, done to the TreeView on the form. (I
>actually found a great example of how ByRef should be used!)
>
>This does require you to trap each of the Form TreeView's events and pass
>the event arguments directly to the corresponding methods of the Class Object,
>like this:
>
>Private Sub tvwExposure_DragDrop(Source As Control, X As Single, Y As Single)
> ' moTreeview is a module level instance of clsTreeView
> moTreeview.ClassTreeview_DragDrop Source, X, Y
>End Sub
>
>On the surface, this sounds like a bit of a hack, but it is operating quite
>well and the code is pretty easy to read since it is close to what would
>otherwise be expected.
>
>I'll keep sloggin' away,
>
>Todd
>http://webpages.mr.net/mitcht/
>
>
>"Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote:
>>Todd -
>>
>>We have come up against this problem, and I hope that it isn't too late
>to
>>change your design.
>>
>>Basically, this behaviour, as Microsoft often says, is by design. "Standard
>>VB" drag drop will only work for controls on a VB container, such as a
Form,
>>UserDocument, UserControl, etc. Another thing you must realise it that
>>within drag drop, VB only sees the "Extender" object that wraps up each
>>control - it cannot see "into" the control, because else this would break
>>COM encapsulation. COM is supposed to be language independent, so we cannot
>>assume that the code inside the control understands VB drag drop.
>>
>>So there are two ways that you can solve this problem: one ideal, one hacky.
>>Guess which one we chose <g>.
>>
>>The "ideal" way is to use the COM standard way to do drag drop. Since
every
>>language or library implements and interfaces drag drop in different ways,
>>Microsoft decided to create a standard way to do this - called OLEDragDrop,
>>in Visual Basic. Luckily, all intrinsic VB controls support this, as do
>the
>>Common Controls OCXs supplied by Microsoft. The majority of modern 3rd
>>party controls do as well, although you ought to check this out to be sure.
>>Behind the scenes, this magic is enacted by requiring a control to implement
>>one or more of the COM interfaces, such as IDragDrop. You won't have to
>>know about these interfaces; however, you ought to know that the mechanism
>>of drag drop is quite different from the VB drag drop mechanism. The latter
>>is based around the concept of dragging controls over and onto other
>>controls. However, OLE drag drop is far more sophisticated, involving
a
>>number of conversations (represented by one of 6 possible events as opposed
>>to VB's two events) between a data source and a data destination. Data
>>sources and destinations can supply data in any of a multitude of formats,
>>which are based on the clipboard formats (and can potentially be extended
>ad
>>finitum). More than one data format can be made available, and the
>>destination can choose one or more of these formats). Many of the VB
>>controls already have automatic support for particular formats. For
>>instance, if you set the textbox's OLEDragMode to Automatic, you can select
>>its text, and drag it. Likewise, a textbox's OLEDropMode at Automatic
>>allows you to drag text into it, and it is automatically inserted.
>>
>>Now this is all well and cool, but what is important for you is that OLE
>>Drag Drop doesn't care about your application's structure. All it knows
>is
>>that if you OLE drag something over a window, regardless of its position
>in
>>a hierarchy of windows, a conversation will be attempted with that window,
>>and so you have a chance to drag stuff into it. So set your TreeView
>>control's OLEDrag to Manual, and get reading the manual!!
>>
>>Of course, it may be too late for that - you have already written tons
of
>>drag drop code. Even so, consider junking it, because despite your loss,
>>you will gain a wonderful flexibility. But, just in case, I should tell
>you
>>how we got round this: The Mouse_Down and Mouse_Move <within> the
>>UserControl code gives the signal to start the drag. However, we don't
>drag
>>the internal tree. Instead, we raise an event, StartDrag, and in the
>>external form's event procedure, we do <TreeUserControl1.Drag 1>. Now,
>all
>>the drag drop is happening on the form. Whenever the
>><TreeUserControl1_DragOver> and <TreeUserControl1_DragDrop> events fire,
>the
>>DragOver and DragDrop method that we have created on the UserControl are
>>called, thus providing us feedback.
>>
>>Personally, this set-up definitely sucks big time, and the more I think
>of
>>it, the more angry I get. If you do it this way, you code becomes very
>>non-portable. It also only works for one level of drag drop. If, for
>>instance, you wanted to further encapsulate <TreeUserControl1> into another
>>UserControl, you would have to write yet more delegation code.
>>
>>
>>Anyway, I hope that this helps.
>>--
>>
>>---------------------------------------
>>Mark Alexander Bertenshaw
>>Programmer/Analyst
>>Prime Response
>>Brentford
>>UK
>>"Todd Mitchell" <Todd.Mitchell@RuckusInteractive.com> wrote in message
>>news:38e7fd15$1@news.devx.com...
>>>
>>> I have created a user control with one constituent control: a treeview.
> I
>>> can drag and drop nodes just fine within the treeview, but once I leave
>>the
>>> bounds of the user control, the mouse icon changes to a no-drop and I
>>can't
>>> raise any dragover or dragdrop events on any other object.
>>>
>>> The same treeview works fine if I put it on a form without being contained
>>> in a user control. I can instantiate multiple instances of said form
>and
>>> drag/drop between the treeviews on the different form instances without
>>any
>>> problem.
>>>
>>> How do I extend the treeveiw drag events beyond the bounds of its
>>container?
>>>
>>> Incidentally I am controlling drag/drop manually and I am not using
>>OLEDrag.
>>
>>
>
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Development Centers
-- Android Development Center
-- Cloud Development Project Center
-- HTML5 Development Center
-- Windows Mobile Development Center
|