Drag Drop using Listboxes – Part 1

[See also Part 2]

Drag Drop in WPF is not so complex once you get used to it…. Usually people blog on how to do drag drop with a canvas, I decided to do the drag drop for 2 listboxes since I think it can be more useful to application developers… + a friend, David Silverlight asked me about it so I decided to blog on it🙂

So for our Drag and Drop exercise we will have 2 Listboxes. A “source” listbox and a “destination” listbox, so that the user can grab an item from the source and put it inside the destination listbox… In order to grab the item from the source listbox we need to handle the PreviewMouseLeftButtonDown event so that when the user holds the mouse left button down we can grab the item. Yet as you might be wondering we need to get the actual UI Element that the user selected (and then get the Content value). For this operation I created a helper method which you can see below…

dragdrop1.jpg

This method will get a UIElement by using hit testing from the point that you specify. Yet if you set a breakpoint and look at the result of the Hit test you will find out that the value that you get from the Hit Test is one of the inner control of the ListBoxItem and not the actual ListBoxItem (for example if you have a TextBlock inside your ItemTemplate of the listbox, you would get the TextBlock). So we need to climb the WPF Visual Tree until we find the ListBoxItem. We are going to do this by trial and error. So we get the UIElement from the Hit Test and pass it to the ItemsContainerGenerator to give us the object source of the ListBoxItem that we are passing. If we do not pass the correct element (i.e if the element that we pass is not the ListBoxItem) the ItemsContainerGenerator will give us back DependencyProperty.UnsetValue, if the return is that we get the Parent from the Visual Tree and try again… Quite simple…

Now that we can get the object value from a point we can grab that value and do the drag drop operation. In order to do this we need to handle the PreviewMouseLeftButtonDown of the “source” listbox as follows

dragdrop2.jpg

So here we grab the object from the “source” ListBox that we want to put in the “destination” ListBox. Then we call the DoDragDrop and pass the source listbox, the data to send in the DragDrop operation and the DragDrop effects.

Now lets implement the Drop. We have to create an event handler for the Drop event of the “destination” ListBox like the following

dragdrop3.jpg

So in the event handler of the Drop all we are doing is to get the data that we passed over with the Drag Drop and push it in the Items collection of the “destination” Listbox. It is very important that to remove the Item from the “source” ListBox you use the ItemsSource and not the Items since that would throw an InvalidOperationException because you cannot change the Items collection while doing drag drop operation on the Listbox. Now it is also important to point out that if you remove an item from the ItemsSource but you ItemsSource is not an ObservableCollection(or any other collection that implements the INotifyCollectionChanged interface), nothing will happen i.e the item will not be removed from the source listbox. Basically by changing the ItemsSource we are relying on the DataBinding for the item to be removed…

I created a demo application for this article and also for Part 2 that I will be writing very soon… maybe even tonight🙂 Part 2 will be more advanced… It will demo on how one can give a preview of the element while dragging to the other ListBox…

Regards

Downlaod Source here

13 thoughts on “Drag Drop using Listboxes – Part 1

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

  2. I found a weird bug in your app. I’ve been experiencing something similar in my app (which is what brought me here). If you shrink your window (or add more items to your list) to trigger the scrollbar on the list, then if you attept to click the scroll bar you get an argument null exception. Any idea how to fix this?

  3. I only get the null reference exception if any of the listboxs that are registered to handle the Drop event is disabled.

    An additional problem I had using this code was that calling DragDrop in the MouseDown event caused all sorts of problems like MouseDoubleClick not firing, extended selectionmode not working properly & taking 2 clicks to select another list item. The solution is to only register DragDrop in the MouseMove event when the dragging is actually to be used like so:

    bool _dragEnabled = false;
    private void MouseMoveHandler(object sender, MouseEventArgs e)
    {
    if (e.LeftButton == MouseButtonState.Pressed && !_dragEnabled)
    {
    _dragEnabled = true;
    //drag drop enabling code
    }
    else if (e.LeftButton == MouseButtonState.Released && _dragEnabled)
    _dragEnabled = false;
    }

  4. Nice article. I don’t pretend to criticize, but there is something missing in your code. What if the user drags one item from the same source/Destiny point ?😉

    Again, thanks, and keep posting your solutions😉
    Ivan Frias

  5. Hi, Nice post and I would like to know 2 things.
    1)How to drag multiple items in Extended mode from onelistbox to another listbox.
    2)With MouseDown drag drop. the items are not getting selected with single click.we have two double clik them.
    can you tel mw how to do these. I am struggling a lot.

  6. i’m not able to remove item from the list, after dropping the data from the listbox0, the code ‘ ((IList)listBox0.ItemsSource).Remove(data); ‘ is not working

  7. what is the use of “allowedsourceeffects” propery in blend? and how it works ?
    what is the use of copy and link propery and allowedsourceeffects?

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

  9. Pingback: [2011.01.05] Drag and Drop in WPF using MVVMLight [II/IV] | fun() things

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