Improved DragDropManager – Source code

The DragDropManger has been a very handy class for me in couple of my projects. Since my last post I made some changes to the interfaces (IDragSourceAdvisor, IDropTargetAdvisor) and also to DragDropManager. There are no major changes except for a few method additions in the interfaces. These methods make it even more flexible.

Changes to IDragSourceAdvisor and IDropTargetAdvisor

Added method: UIElement GetTopContainer();

In my previous version I had assumed there would be only one MainWindow. Hence I was using Application.Current.MainWindow as my default top container. Of course this assumption worked well for some of my projects but broke when I had to do DnD across windows. This lead me to add the GetTopContainer() method, which is queried for the right container (AdornerDecorator).

How is this useful? Say for example you have a DragSource in one window and a DropTarget in another window. When an element in dragged onto the target window, the location of the feedback-UI is no longer relative to the MainWindow, instead it is relative to the target window. By querying the IDropTargetAdvisor for the top-container we can see the feedback-UI at the right place.

[Note] If you are using just the MainWindow, you can return Application.Current.MainWindow as your top container.

Added read-only property ApplyMouseOffset to IDropTargetAdvisor

When an element is moved from the source to the target, the initial click on the source-element may be at an offset inside its bounding-box. If the same offset needs to be applied to the feedback-UI on the target, the property ApplyMouseOffset can be set to True. In most cases you would set it as True. To accommodate a few outlier cases, this property had to be added.

That is all for the changes. I hope you find the code useful.  If you do anything cool with it, I would love to know and shower praise on you ;)

Download DragDrop.zip

Technorati Tags: , ,

Similar Posts:

41 responses to “Improved DragDropManager – Source code”

  1. Pavan Podila

    Thanks for the link Conrad. Definitely something to keep in mind. The version of DragDropManager I have, already has the right Type. Not sure where the mismatch was caused.

  2. Conrad
    Hi Pavan,
    I discovered the source of Toon’s problem with the Visual Studio 2008 designer.  The root cause seems to be that the designer is smart enough to match up the types specified in the SetDropTargetAdvisor() and SetDragSourceAdvisor() methods with the types specified in the attached property registration.
    In the registration, the property has type IDropTargetAdvisor and IDragSourceAdvisor, but in the Set methods the second parameters are of type bool.  Changing the second parameters of the Set methods to the correct types gets the designer to play nice again.
    Conrad
  3. Pavan Podila

    Yes the jitter is something I have been trying to fix but haven’t got the chance. Busy with other projects :(
    Removing the DragLeave might be a problem since I do some cleanup on the adorner. You can definitely use one class that implements both the interfaces…Hope that answers your questions…

  4. (no name)

    Hi, thanks for the great code.

    I tried using the code with one canvas as source and target. I’m using some buttons as drag able elements.
    It works fine but i get a lot of jitter when moving the buttons over other elements.
    I debugged a little and found out that removing the "DragEventHandler" DropTarget_PreviewDragLeave
    solves the problem.
    In the classes implementing IDropTargetAdvisor and IDragSourceAdvisor I’m not really sure what to return
    on function call GetTopContainer(), so I’m using "Application.Current.MainWindow.Content as UIElement;"
    which I found in your older version of the code. Is that correct?
    Do you think it will be a problem removing the DragEventHandler or do you thing I can solve the problem
    maybe by implementing one class that implements both interfaces IDropTargetAdvisor,
    IDragSourceAdvisor?

    Greetings Thomas

  5. Pavan Podila

    Hi Toon,
           That is interesting and looks like a Designer issue. Hope you are not facing issues at runtime.

  6. (geen naam)
    Hi Pavan
    Very nice library, and it is working well.
    there is only one small problem in visual studio 2008. I get the error: 
    The property ‘DragDropManager.DragSourceAdvisor’ is read-only and cannot be changed.
    This happens when you reload the designer
    is this a known error?? I have tried to solve the problem but didn’t get it right
    maybe you have the answer?
    thanks
    Toon
     C:\sources\priva\software\pc\Ows\Source\OwsClient\PageEditor\PageEditor.xaml 88 17 OwsClient.PageEditor
     in visual studio 2008
  7. Jeremiah Morrill
    Thanks for checkin out my blog!  Though the MediaElement -> DirectShow interop and the BitmapSource buffer are really my only claims to fame.  Contrasted, everything you have on your blog seems to be a gem.  Sometimes its fustrating seeing these great screen captures and no code.  Though it has brought a lot of inspiration.  I was able to make my own element flow, but I admit the WPF best practices went right out the window!
    The ElementMorph isn’t really technologically braggable.  Simply its a grid, with two viewboxes inside.  Morphing from the first item to the second, the grid resizes from the size of the first item, into the size of the second, fading the two along the way.  When you get a chance, in OSX, just notice how the widget icon changes when being dragged over the droppable area…that’s pretty much what I have…Nothing special, but the effect is pretty nice for how much work it needs.
    About the always visible preview adorner for the DnD, I’ll keep stabbing away at it.  If anything comes to mind, I would definatly appreciate it.
    -Jer
  8. Pavan Podila

    Hi Jer,
          I had a chance to quickly browse your blog … pretty interesting stuff that you have up there. BTW I would love to see your morph control that you have created. In fact even I have been doing something similar using bitmap-sources. Would love to see what you have done.

    As regards the DnD stuff, I would definitely give it a shot. Its definitely doable. Let me have a closer look at what MacOSX does…

    Feel free to mail me at pavan [dot] podila [at] gmail [dot] com

  9. Jeremiah Morrill
    When I first started WPF a drag/drop control was the first thing I made.  Then I came across your solution and I could tell instantly how horrible mine was.
    I have been using this ever since.  It is excellent!
    I have been trying to make a few enhancements, but not getting much success.  I want to give more visual feedback during the drag "experience". 
    For instance, I made a simple control that morphs between two visuals, very similar to the effect in OSX when you drag a widget from the list and it morphs from the widget icon to the actual widget.  This "element morph" control I start the morph and return it in "DropTargetAdvisor.GetVisualFeedback".  The problem is that when I leave the drop area I would like to morph the item back, but instead the element (the preview adorner) disappears.  It would be great if the preview adorner was always visible during the drag/drop operation.  Then one of the DnD interfaces would receive messages of a "drag state change", ie IsOverDroppable, IsNotDroppable, DropCancelled, DropFinished so that the element in the preview adorner could react to state a bit better.
    I guess most of this functionality is already there or easy to implement, but keeping the preview adorner visible at all times is my show stopper for these wild ideas.  Any suggestions on how I might be able to do this?
    Anyways thanks for the great DnD framework.  It is now a permanent part of my WPF toolset :) .
    -Jer
  10. Pavan Podila

    Hope it meets your needs :) Do let me know. Thanks!

  11. (no name)
    Thanks for posting the source to this. I’m going to try implementing this method in a multi window docked interface w/ some grid controls and stuff for a Computer aided dispatch system. I’ll let you know how it goes. Looks pretty good so far.
  12. Kennis

    nice example!! Pavan have you tried or know how to implement when an element (can be stackpanel) inside the canvas that is draggable can be at a time parent of other elements, this mean by we can drag more elements into this element.

  13. Kennis

    Ok, I really appreciate if you can give a hand help to me since i have tried everything and it doesn’t work to me =(

    let’s say we have CanvasA as the main container, inside this canvasA we have StackPanelA and StackPanelB, I need to perform thse actions at the same time:

    -move StackPanelB to StackPanelA, so stackpanelB will be child of stackpanelA.

    -move elements of stackpanelB to stackpanelA,
    so element from stackpanelB will be child of stackpanelA.

  14. Kennis

    Hey Pavan, I am not sure what classes you are using to implement this, in the attached file I have four files: DragDropManage, IDragSourceAdvisor, IDropTargetAdvisor and DropPreviewAdorner.
    Because I am not sure how to get it work with the UI, I took from your previews post from Lester’s class called “CanvasDragDropAdvisor” to set as DragSourceAdvisor and DropTargetAdvisor for those containers that can be target and source at the same time. Something like this:

    …(stackPanelA and stackPanelB)

    the problem I have here is that the canvasA has drag and source advisors so that we can move the stackpanels, but when I want to move stackpanelB to stackPanelA, it doesn’t really embed to stackPanelA, stackPanelB is still child of canvasA and not child of stackPanelA.

    I really appreciate if you can put some code so that I can get better understanding.. thanks again man!!

  15. Kennis

    sorry about the …

    …(stackpanelA and stackPanelB)

  16. Pavan Podila: http://codeplex.com/FluidKit - WPF controls, etc... - Rob Relyea - Xamlified

    [...] ( Part 1, Part 2, Part 3, Part 4, Part 5, Part 6 [...]

  17. ravi

    Hi Pavan,

    First of all, let me thank you for your blog. It’s been wonderful to me. Loads of WPF stuff. Amazing work! Congratulations and thank you for opening it to the world.

    Secondly, I am windows programmer and quite knew to WPF. Recently, I have to develop an application that supports drag and drop functionality. I am googling all the days but did not get the one that is close to my requirement. Since, you have developed a library on drag and drop, I thought you would help me showing some direction.

    Here are the simple requirements (they seem so difficult for me:) ).

    1. My application must stay on the system tray. While it stays like a tray icon, it should act like a drag bin ( accept files dropped on to it – act like a drag target).

    2. When my application exe placed on the desktop, I should be able to drop a file on the desktop item (my app exe).

    In both cases, my app takes the dropped item and copies to somewhere else.

    That’s it…. I am having hard time making the sys tray icon act like a drop source. Similarly the desktop icon.

    I would be really greatful to you if you could shed some light on these issues.

    Looking forward,
    Thanks a million in advance,
    Ravi.

  18. ravi

    - a typo in my previous post. Please read the following line…

    “…That’s it…. I am having hard time making the sys tray icon act like a drop source. Similarly the desktop icon.”

    as

    “…That’s it…. I am having hard time making the sys tray icon act like a drop TARGET. Similarly the desktop icon.”

    I meant that the tray icon and desktop icons act like a drop target.

    Sorry and thanks a gain.

  19. Darren

    Ravi,

    This library is just what the WPF doctor ordered – thank you! Just one suggestion and one question:

    If this library is implmented within a modal dialog (for example), it doesn’t work correctly as the GetTopContainer() method returns the Main Window content. Instead, I found it better to cycle through the Windows in Application.Current.Windows until I found the on marked as IsActive and return that.

    Now the question: Is it possible for the DragSourceAdvisor to know where the item is being dropped in its FinishDrag() method? I am building a visual filter builder, and filters can be dragged into a panel (resulting in a filter being added to the panel) and dragged out of the panel (resulting in the filter being removed). Problem is, since this panel is both a DragSource and a DropTarget , a slight movement of the mouse when clicking a filter within the panel causes FinishDrag() to fire, removing the filter. Any suggestions?

    Thanks again.

  20. Toon

    Hi Pavan,
    it’s been a while but finally some reply from me
    The problem i had send you on 30 November 2007 is solved. Conrad was right and gives the solution.

    I think the jitter problem can be solved: when creating the overlayElement give the position
    something like this:
    private static void CreatePreviewAdorner(UIElement adornedElement, UIElement feedbackUI, Point point)
    {
    if (overlayElement == null)
    {
    AdornerLayer layer = AdornerLayer.GetAdornerLayer(currentDropTargetAdvisor.TopContainer);
    overlayElement = new DropPreviewAdorner(feedbackUI, adornedElement) {Left = point.X, Top = point.Y};
    layer.Add(overlayElement);
    }
    }

    Now I have only one question left: how can i remove in code a DragSourceAdvisor/DropTargetAdvisor?

    greetings Toon

  21. Prashant V C

    Hey Pavan,

    I’m trying out ur DragDrop manager for the treeview items, but finding it difficult use it, is this really work with treeview

  22. PRT

    Hi Pavan,
    U created really cool stuff,
    i’m trying to use in scenario where i want to drag element from wpf form n drop it on windows form, will it work in this scenario.

    if u provide sample it really help full for me

    Thanks,
    PRT

  23. Michael

    Hi Pavan,
    Thanks for your great library.
    How can I drag listboxitems which are binded to collection data? Following code seems not work

  24. Michael

    Sorry for previous post. It seems that I cannot write xaml code here.
    My question is:
    How can I drag listboxitems which are bound to collection data. Simply adding the attatched property to the ListBox seems not work.

  25. Michael

    Thank you. Hope the new version will come out soon.

  26. Justin

    Thank you so much for your code which is very helpful. :)

    I put 10 images in my listBox which is inside a ScrollViewer separately.
    But My listbox shows only 5 images, and I want to move 1st image to the last position.
    For that, first I drag the 1st image, and move my mouse down towards the last position. However, even though I moved my mouse down, the scroll bar didn’t move at all.

    Would you let me know how can I solve this problem?

    I appreciate it for your help.

    - Justin

  27. Mark

    Pavan,

    This library has been very useful. One problem I am having though is with the drop target not receiving mouse events because they are trapped by DragDropManager.

    I am assigning a user Canvas control as my drop target, and I need the control to receive mouse events to leverage custom control functionality during the drag drop operation. I’ve tried adding a handler to the control with the HandledToo option, but it still does not receive the desired events. I saw that you solved a similar problem with scrolling by removing the scrollbar from the Control Template, but this doesn’t appear to be an option in my case. Do you have any ideas how this problem may be solved?

    Thank You for any suggestions you may have!

    Mark

  28. Geronimo

    Hey Pavan,

    excellent library!

    I’m planning to use it to be able to drag en drop custom usercontrols between panels. I modified your library a little to support this. However when serializing the usercontrol we loose events that are setup on for example the Click event of a button.

    I changed your code to pass my custom control rather than the serialized xaml string. I’m keeping errors when the OnMeasureOverride is called in the DropPreviewAdorner. (Must disconnect specified child from current parent Visual before attaching to new parent Visual.)

    Is there anyone who has succesfully created an app supporting drag en drop of usercontrols while remaining events in the child controls of the usercontrol being dragged?

    Regards, Geronimo

  29. Cris

    Hi Pavan,
    I love your drag and drop solution. I have modified the CanvasDragDropAdvisor class a bit to fit my needs, but I run into some problems.
    I have a user control containing an ItemsControl databound to a collection of controls (Buttons for example – their type is not really important). the ItemsControl.ItemsPanel is set to a canvas.

    Now from my main window I have a number of options to create some tool windows. Each of those tool windows contain an instance of my user control described above (amongst other things). Your solution uses main application’s AdornerLayer. This solution does not seem to work with undocked tool windows. I have tried a number of work around but I could not get it to draw the adorner of the items dragged while in floating tool windows. If I am docking those windows within the main window it works just fine.
    Could you, please, help me with an idea?

    Thank you for your time,
    Cris

    1. Cris

      By “it doesn’t work” I mean I can get the adorner to be drawn. The actual drag and drop works just fine.

    2. Cris

      can’t*

      damn typos :)

  30. K.S. GIRI

    I am trying to contact my good old school and college friend from Visakhapatnam,Mr.P.Ravi, who is an Engineer and his elder brother Dr.Sharma. In case if you are related to them please give me mail – Thanks

  31. Adriana

    “No problem Michael, I was able to catch your idea.

    The DragDropManager does not natively support DnD on a ListBox. It requires some extra work, partly because ListBox eats up the mouse events.

    I have a working version in an internal build; will see if I can dig it up.”

    I’m having this same issue as Michael regarding the listbox. Did you have some help here?

    thank you

Leave a Reply