Drag & Drop in WPF.. part 3 .. the results and code...
Here is where we take every thing learned in Part1 (the drag) and Part2 (the drop) and package it into more realistic scenarios...
Let's first begin by walking through a few items we skipped in earlier parts for brevity:
Detecting DragDropEffects...
When you start a drag, you should check if Ctrl or Shift are pressed... Each one of these being pressed implies a different action for our drag operation...
|
Detecting what needs to be dragged:
Deciding what needs to be dragged is sucky because you almost always have to put app knowledge into your drag & drop code.. There is not a one size fits all..
For example: <Button Content="Test" /> will generate a tree that looks like: Button - > Chrome - > Content Presenter - > TextBlock ...
So, if you hitTest on what is visible, you might get the TextBlock when what you wanted was the button ....
I don't have a great answer for this. As I mentioned, my approach is to lazily shoot for the OriginalSource element in the MouseMove event handler.. This seems to work slightly better than doing HitTesting (where I could get an item lower in the tree like the TextBlock ..
For those that do want to do hittesting, the code is trivial:
Doing Drag & drop should be about data:
I have to emphasize d&d was meant for data.. In the demo below I make the mistake of letting you drag UIElements and the like.. This is for illustration purposes... imho if you find yourself trying to drag any thing other than data, you should evaluate decoupling presentation and data..
Now onto a real sample...
What I have done for my demos is create a library with:
- DragHelper class: given a source (any UIElement) will subscribe to handle the required events to initiate a Drag& Drop operation.
- DropHelper class: given a target ( any UIElement) will set properties needed & subscribe to required events to complete a Drop operation...
- DragAdorner -- same as previous examples, the class to draw the Adorner while element drags..
I have also defined an interface that a class can implement to aid in the dragOperation...
|
This interface gets called back from either DragHelper or Drophelper (whenever needed)
A few things to notice:
-
the interface is not necessarily implemented by either the source or the target. it is de-coupled from both. Any other class can implement it and it can be generic.
-
The interface is optional, if you do not implement it, the helpers classes will do their best to help.. My advise is always implement the GetData ( ) part of the interface.
-
You can implement just part of the interface. DragDropProviderActions is a flag that says what actions the interface supports..
Wiring the 'helpers'
Is pretty trivial ... the constructor for DragHelper looks like this:
Here are examples of using the constructors... ( DropHelper I did not explain above beccuse the only parameter in is the drop target control itself..
For the most part, these classes do what we discussed .. the exception is the drop..
Common drop issues:
Drop of data is straight forward... there is no generic recipe for all scenarios but two that I use often are: dropping to ContentControl or dropping to ItemsControl.. in which case I set appropriate property or add the data to the items collection ..
Drop of UIElements is slightly trickier mostly because you need to re-parent your element to the target.. . The sample classes use the IDataDropObjectProvider to Unparent () the UIElement before dropping it..
Note that this assumes every thing is in process, the interface passes UIElements and other stuff around ... To implement an Out of process handler for passing UI, you can make COM objects and pass that around..
The sample
Is not pretty ... but quite functional. .. Here is the first half ..
The second half of the app is even uglier, it is in Window2.xaml but it is a common scenario...
OK that covers my D&D walk through ... The source for the sample in part 3 is here..
{let me know if you find bugs or issues }
Comments
Anonymous
July 12, 2007
Cookieless Session with ASP.NET Ajax and Web Services [Via: derek ] Displaying Extended Details in a...Anonymous
July 14, 2007
in reading your posts i swear you stole my code... it's literally the exact same stuff. even down to the "DragHelper" class name -- mine is called PreviewDragHelper. but the constructs are all pretty much identical. i guess great minds think alike. either that, or we are both off our rockers. ;)Anonymous
July 29, 2007
Hey Eric, Sorry for belated reply.. as you know I was on vacation... The adding "Helper" to a class or namespace is a coincidence, I do it all the time .. That said, the code should look familiar; it is a compilation of many samples I have seen or helped on to our early adopters (every thing proprietary removed of course) To credit most people I can think of who have directly or indirectly contributed: Robby Ingebrestein (Pfizer project), Josh Smith (his articles on WPF).. Yourself and any other Yahoo folks (out of proc stuff ), Florian Kruesch (OTTO project), and other microsoft folks like Sang Il, LLobo, and Marcelon... Also, the "planets" images and XML file comes from a sample Bea used.. it is just easy databinding so I use that alot .. Why so many? The goal from this was to explain as many options as we could, so I went as broad as I could.. That said, the code is not complete.. I mostly took points to illustrate, so not designed to be reusable as a library.. Saludos,