Drag Drop using Listboxes – Part 2

In this post I will demo on how one can create a more advanced Drag Drop for ListBoxes than the one I posted earlier here.

Basically what we will do in this post is to create an Adorner for the ListBoxItem being dragged.We will have to create our own Adorner in order to show the ListBoxItem being dragged and then add that Adorner instance to the Parent control that is holding both the “source”ListBox and the “destination” ListBox. I got most of the code for this from here.

So let us start by creating the Adorner class. What we want is to display the ListBoxItem in the Adorner layer of the parent control yet we cannot just use the ListBoxItem from the original listbox because a UI Element can only belong to a single Visual Tree. So what we will do is Clone the ListBoxItem. This is very easy since a ListBoxItem is nothing more than a Content Control, so we can copy the Content and also use it’s ContentTemplate to create a Clone.

advanceddragdrop1.jpg

As you can see this helper method is doing nothing more that create a new ContentControl and setting the Content property and the ContentTemplate property from the Element that is passed and that is our Clone of the Item Selected.

Usually when using Adorner you would go ahead and do your own drawing yet in our case we are going to create a Content control and display it so we must make sure that the Layout system knows about this control. In order to do this we have to override 2 methods the MeasureOverride and the ArrangeOverride like this

advanceddragdrop2.jpg

Where elementToShow is just a reference to the ContentControl that we have created by using the CreateClone method.

Now we need to override another 2 methods so that WPF can get the elementToShow and render it.

advanceddragdrop3.jpg

Ok so by now we already have something showing up on screen. Yet right now the elementToShow is being displayed at a relative position to the AdornedElement. We would want the elementToShow to move around while dragging just like in Windows Explorer when you drag a file. So lets create a method that we can call from outside and pass the new coordinates to the Adorner.

advanceddragdrop4.jpg

Ok, so the UpdatePosition is just a method that one can call from outside the Adorner to update the position for the element. There is another method in the above code, GetDesiredTransform. We need to override this method in order to ask WPF to render our elementToShow at the point that is specified to us by the UpdatePosition method . All we need to do is create a TranslateTransform and specify the new coordinates. Without the TranslateTransform the elementToShow would be rendered relative to the Adornered element.

Ok and that is all for our Adorner, now lets have a look on how we can use it…

As explained in Part 1 of this post we need to handle the PreviewMouseLeftButtonDown of the “source” ListBox in order to grab the item to be dragged over to the “destination”ListBox. This time we will also create an instance of the adorner class we just built and add it to the AdornerLayer of the control that is parent to both the “source” ListBox and the “destination” Listbox.

advanceddragdrop5.jpg

Now that we have added the Adorner to the AdornerLayer, we only need to ask out beloved Adorner to update the position so that the elementToShow in the Adorner would move around accordingly. We will do this by handling the DragOver event of both the “source” and the “destination” ListBoxes

advanceddragdrop6.jpg

All other code is just like the Part 1 code that I have explained. The only differnce is that now we also have to remove the Adorner from the Adorner Layer once the item is Dropped on the “destination” ListBox(or even if it is dropped on the “source” ListBox since that would be like a cancel for us).

Regards

Download Source Code Here

About these ads

8 thoughts on “Drag Drop using Listboxes – Part 2

  1. Pingback: Drag Drop using Listboxes - Part 1 « C# Disciples

  2. Good work! As I implemented this code in a Contact app I was writing (just to become familiar with WPF) I found it was missing one thing: a properly sized adorner.
    My ListBox uses a DataTemplate with a left aligned 48×48 image control with a border and 4 TextBlocks to the right of the Image for the contact info. When I would click a list box item, the adorner appeared with a very tall, narrow image border with the 48×48 image centered in it, and the TextBlocks were top-aligned. Needless to say it was not correct.

    So, I added the following code to determine the size of the original ListBoxItem and apply that to the adorner.

    Add these variables to the AdornerDragDrop class:
    double height;
    double width;

    In the AdornerDragDrop() constructor, insert the following code:

    //store the dimensions of the original item
    FrameworkElement item = (FrameworkElement)elementToShow;
    height = item.ActualHeight;
    width = item.ActualWidth;

    And finally in MeasureOverride() insert the following code before the call to Measure():

    //size the adorner properly
    constraint.Height = height;
    constraint.Width = width;

    This will cause the adorner’s size to match the original ListItem’s size.

    Now I just have to resolve the issue of dragging the item over non-ListBox controls in the window…

  3. I have a user interface with a grid with 8 rows and 3 columns. I have two list boxes which are elements of stack panels in different parts of the parent grid. When I use the adorner class I can see the adorned element I am dragging but it is miles away from the mouse pointer. How do I correct this behaviour. Is it connected to the parameter I pass to the adorner constructor:- adorner = new AdornerDragDrop(*****, dataContainer); I pass the main grid of my app and get this incorrect behaviour.

  4. I am using your implementation with a ListView using the MVVM design pattern. The ItemsSource objects contain buttons with bindings, however the DragDropManager doesn’t allow the command to fire (assuming the event is being intercepted). Any suggestions?

  5. I tried implementing this code with multiple list boxes. I have a strange issue in which if I drop the dragged item in non draggable position, then it leaves the Adorner as it is. It does not remove it. Please guide me how can I avoid this. Thanks.

  6. Pingback: WPF Drag and Drop | David's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s