Click here to Skip to main content
11,570,352 members (49,855 online)
Click here to Skip to main content

Drag and Drop in WPF

, 7 Nov 2009 BSD 136K 12.4K 76
Rate this:
Please Sign up or sign in to vote.
An article showing how to add drag and drop to a WPF application using the GongSolutions.Wpf.DragDrop library.

Introduction

For a while, I've been lamenting the lack of decent drag and drop support in WPF. While WPF has advanced desktop GUI programming considerably from the days of WinForms, drag and drop hasn't changed since I started programming on Windows with Visual Basic 3.0.

In particular, one must litter code-behinds with drag and drop logic, something that is anathema to any self-respecting WPF developer in the days of MVVM.

After putting up with this for a while, I came across an article by Bea Stollnitz on using attached properties to add drag and drop logic to controls in XAML. However, Bea's solution did not go as far as I needed for my purposes. What I needed was:

  • MVVM support: Anything more than basic drag drop operations need logic, and code-behind isn't the right place for that logic. Decisions about what can be dragged and what can be dropped where should be delegated to ViewModels.
  • Insert/Drop Into: Sometimes when you drag an item from one place to another, you're re-ordering the items in a list. At other times, you're dropping one item onto another, like dropping a file into a folder in a file manager.
  • TreeView support
  • Multiple selections
  • Automatic scrolling

Looking around, I couldn't see anything that satisfied my needs, so I decided to write one. You can find the latest source code with examples at the Google Code project. It's licensed under the BSD license, so you're free to use it pretty much however you like.

Using the Code

To demonstrate the use of the drag drop framework, let's use a simple Schools example. In this example, we have three ViewModels:

  • MainViewModel: This simply contains the collection of schools.
  • SchoolViewModel: A school has a name and a collection of pupils.
  • PupilViewModel: A pupil has a name.

In our UI, we'll display two listboxes. The first to display the list of schools, and the second to display the list of pupils belonging to that school. Our XAML looks like this:

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    
    <ListBox Grid.Column="0" 
       ItemsSource="{Binding Schools}" 
       DisplayMemberPath="Name" 
       IsSynchronizedWithCurrentItem="True"/>
    <ListBox Grid.Column="1" 
       ItemsSource="{Binding Schools.CurrentItem.Pupils}" 
       DisplayMemberPath="FullName"/>
</Grid>

And the resulting window looks like this:

gong-wpf-dragdrop1.png

Firstly, we want to be able to re-order the pupils in the second ListBox. This is done by setting the IsDragSource and IsDropTarget attached properties on the ListBox:

<ListBox Grid.Column="1" 
  ItemsSource="{Binding Schools.CurrentItem.Pupils}" 
  DisplayMemberPath="FullName"
  dd:DragDrop.IsDragSource="True" 
  dd:DragDrop.IsDropTarget="True"/>

You will now be able to drag and drop items within the ListBox to re-order them. Now, you might suppose that if you were to set the IsDropTarget property on the first ListBox, you'd be able to drag a pupil into a school. However, try doing this, and you won't be allowed. That's because the first ListBox is bound to a collection of SchoolViewModel objects whereas the second ListBox is bound to a collection of PupilViewModels. What should happen here? The framework doesn't know, so we're going to have to tell it.

Enter DropHandlers

To add a drop handler to the ListBox, we set the DropHandler attached property on the first ListBox, and bind it to a ViewModel. In this case, we'll just bind it to the MainViewModel, like so:

<ListBox Grid.Column="0" 
  ItemsSource="{Binding Schools}" DisplayMemberPath="Name" 
  IsSynchronizedWithCurrentItem="True"
  dd:DragDrop.IsDropTarget="True" dd:DragDrop.DropHandler="{Binding}"/>

Now we need to add the handling code to MainViewModel. To do this, we implement the IDropTarget interface. This interface defines two methods: DragOver and Drop. DragOver is called whilst the drag is underway, and is used to determine whether the current drop target is valid:

void IDropTarget.DragOver(DropInfo dropInfo)
{
    if (dropInfo.Data is PupilViewModel && 
        dropInfo.TargetItem is SchoolViewModel)
    {
        dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
        dropInfo.Effects = DragDropEffects.Move;
    }
}

Here, we're checking that the dragged data is a PupilViewModel, and the item that is currently the target of the drag is a SchoolViewModel.

The dropInfo.Data property contains the data being dragged. If the control that was the source of the drag is a bound control (which it is), this will be the object that the dragged item was bound to. The dropInfo.TargetItem property contains the object that the item currently under the mouse cursor is bound to.

If the data types are correct, we go ahead and set the drop target adorner. Because dropping a pupil into a school causes the pupil to be added to the school, we choose the Highlight adorner which highlights the target item. The other available drop target adorner is the Insert adorner, which draws a caret at the point in the list the dropped item will be inserted, and is what you see when re-ordering pupils in the second ListBox.

Finally, we set the drag effect to DragDropEffects.Move. This tells the framework that the dragged data can be dropped here and to display a Move mouse pointer. If we don't set this property, the default value of DragDropEffects.None is used, which indicates that a drop is not allowed at this position.

Next, the Drop method:

void IDropTarget.Drop(DropInfo dropInfo)
{
    SchoolViewModel school = (SchoolViewModel)dropInfo.TargetItem;
    PupilViewModel pupil = (PupilViewModel)dropInfo.Data;
    school.Pupils.Add(pupil);
}

Here, we simply get the SchoolViewModel and the PupilViewModel that are involved in the drop from the DropInfo parameter, and add the pupil to the school. We can be sure that the data is going to be of the expected type because the DragOver method has already filtered out any other situation.

Oh! But hold on, when we drop the pupil into the new school, we're not removing him from the previous school, i.e., we're copying instead of moving. To remove the pupil from the previous school, we need to be able to get hold of the collection from which the drag was initiated. This is provided by the DropInfo.DragInfo object. This object holds information relating to the source of the drag. In particular, we're interested in the SourceCollection property:

((IList)dropInfo.DragInfo.SourceCollection).Remove(pupil);

That's All For Now Folks

That completes this introductory article. You can find more examples in the Google Code project. Some features to look out for:

  • Drag handlers
  • Drop adorners
  • Multiple selections

If this article interested you, please join in! Post to the Google Groups, or contribute code to advance the project, and hopefully, we can make something that can be drag and dropped screaming out of the 20th century.

License

This article, along with any associated source code and files, is licensed under The BSD License

Share

About the Author

Steven Kirk
United Kingdom United Kingdom
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Kim Togo29-Aug-13 3:10
memberKim Togo29-Aug-13 3:10 
QuestionDragging and dropping to and from a usercontrol and an itemscontrol Pin
LooLooClement17-Aug-13 4:09
memberLooLooClement17-Aug-13 4:09 
GeneralA thing of beauty Pin
Dijj7-Jun-13 23:19
memberDijj7-Jun-13 23:19 
Questioncan't unselect item from mutiple selected items in ListBox Pin
srikanth.chippa5-Mar-13 0:55
membersrikanth.chippa5-Mar-13 0:55 
QuestionIssue with TabControl Pin
Coxianuk27-Feb-13 6:59
memberCoxianuk27-Feb-13 6:59 
GeneralMy vote of 5 Pin
Wayne Gaylard4-Jan-13 0:45
mentorWayne Gaylard4-Jan-13 0:45 
GeneralMy vote of 5 Pin
Jecho Jekov30-Sep-12 19:43
memberJecho Jekov30-Sep-12 19:43 
Questiondon't work correctly Pin
michaelgr130-Jun-12 21:02
membermichaelgr130-Jun-12 21:02 
Questiondragging to a child in a treeview Pin
boogster71427-Mar-12 1:05
memberboogster71427-Mar-12 1:05 
QuestionCan't Get It To Work Pin
Kevin Marois1-Mar-12 12:29
memberKevin Marois1-Mar-12 12:29 
GeneralMy vote of 5 Pin
Member 867759026-Feb-12 3:14
memberMember 867759026-Feb-12 3:14 
QuestionExcellent! Pin
caliban2621-Jan-12 0:37
membercaliban2621-Jan-12 0:37 
QuestionGREAT! Pin
Member 84445886-Jan-12 9:53
memberMember 84445886-Jan-12 9:53 
GeneralMy vote of 5 Pin
alfredjkwack27-Nov-11 16:29
memberalfredjkwack27-Nov-11 16:29 
GeneralMy vote of 4 Pin
earvella20-Nov-11 20:17
memberearvella20-Nov-11 20:17 
QuestionWhat to do if Droptarget is itunes... Pin
goodreason13-Oct-11 9:51
membergoodreason13-Oct-11 9:51 
BugReordering the Schools ListBox ? Pin
Raul Dsouza16-Aug-11 23:34
memberRaul Dsouza16-Aug-11 23:34 
NewsI just posted a project that uses your drag drop tool. Pin
DannyStaten13-Aug-11 5:29
memberDannyStaten13-Aug-11 5:29 
QuestionDrap n Drop Pin
c#_cool25-Jul-11 7:23
memberc#_cool25-Jul-11 7:23 
QuestionCan DropTarget be a canvas? Pin
Iman A18-Jul-11 19:52
memberIman A18-Jul-11 19:52 
GeneralRe: Can DropTarget be a canvas? Pin
Thomas_M15-Aug-11 2:34
memberThomas_M15-Aug-11 2:34 
AnswerRe: Can DropTarget be a canvas? Pin
Thomas_M7-Sep-11 4:14
memberThomas_M7-Sep-11 4:14 
GeneralRe: Can DropTarget be a canvas? Pin
Iman A7-Sep-11 13:43
memberIman A7-Sep-11 13:43 
Generalwith VS2010 anf Wpf 4.0 Pin
anthride8-Jun-11 6:40
memberanthride8-Jun-11 6:40 
GeneralGood work Pin
anthride8-Jun-11 6:32
memberanthride8-Jun-11 6:32 
Questionlicense? Pin
Member 767239314-Feb-11 5:35
memberMember 767239314-Feb-11 5:35 
GeneralHaving trouble with TreeView Functionality Pin
OffApps20-Jan-11 5:02
memberOffApps20-Jan-11 5:02 
GeneralMy vote of 5 Pin
stooboo29-Nov-10 5:47
memberstooboo29-Nov-10 5:47 
Does what it says on the tin ... drag n drop working with custom handlers in mvvm scenario in about 5 mins from downloading it ,, NICE !
Generaldrag not working in wpf control hosted in win forms Pin
Daemon44429-Oct-10 2:31
memberDaemon44429-Oct-10 2:31 
GeneralCrashing when I want to drag and drop between two collections on the same viewmodel [modified] Pin
DannyStaten22-Oct-10 17:28
memberDannyStaten22-Oct-10 17:28 
GeneralRe: Crashing when I want to drag and drop between two collections on the same viewmodel Pin
Daemon44431-Oct-10 21:34
memberDaemon44431-Oct-10 21:34 
GeneralRe: Crashing when I want to drag and drop between two collections on the same viewmodel Pin
DannyStaten3-Nov-10 4:32
memberDannyStaten3-Nov-10 4:32 
QuestionAwesome... how do I keep my double click event from getting lost though? Pin
DannyStaten12-Oct-10 12:09
memberDannyStaten12-Oct-10 12:09 
GeneralRe: Awesome... how do I keep my double click event from getting lost though? [modified] Pin
DannyStaten12-Oct-10 12:31
memberDannyStaten12-Oct-10 12:31 
GeneralRe: Awesome... how do I keep my double click event from getting lost though? Pin
Steven Kirk12-Oct-10 21:57
memberSteven Kirk12-Oct-10 21:57 
GeneralRe: Awesome... how do I keep my double click event from getting lost though? Pin
thegrid.ch31-Aug-11 21:19
memberthegrid.ch31-Aug-11 21:19 
Generalanimating while dragging Pin
Member 459998124-Sep-10 10:00
memberMember 459998124-Sep-10 10:00 
GeneralRe: animating while dragging Pin
Steven Kirk24-Sep-10 15:05
memberSteven Kirk24-Sep-10 15:05 
GeneralRe: animating while dragging Pin
Member 459998124-Sep-10 16:58
memberMember 459998124-Sep-10 16:58 
Generalneed the feature of editing Pin
hjy121016-Apr-10 17:35
memberhjy121016-Apr-10 17:35 
Questionsetting IsDragSource only on certain nodes of a TreeView Pin
Guy Shtub17-Mar-10 7:13
memberGuy Shtub17-Mar-10 7:13 
AnswerRe: setting IsDragSource only on certain nodes of a TreeView Pin
Steven Kirk18-Mar-10 2:52
memberSteven Kirk18-Mar-10 2:52 
GeneralRe: setting IsDragSource only on certain nodes of a TreeView Pin
Guy Shtub20-Mar-10 22:58
memberGuy Shtub20-Mar-10 22:58 
Generalusing the Visual as feedback Pin
Guy Shtub16-Mar-10 6:11
memberGuy Shtub16-Mar-10 6:11 
GeneralRe: using the Visual as feedback Pin
Steven Kirk18-Mar-10 2:55
memberSteven Kirk18-Mar-10 2:55 
GeneralRe: using the Visual as feedback Pin
Guy Shtub20-Mar-10 23:02
memberGuy Shtub20-Mar-10 23:02 
GeneralLittle DropHelper<T> Pin
Manuvdp27-Feb-10 21:33
memberManuvdp27-Feb-10 21:33 
GeneralRe: Little DropHelper Pin
Louis Gale10-Aug-10 20:42
memberLouis Gale10-Aug-10 20:42 
GeneralRe: Little DropHelper Pin
Steven Kirk11-Aug-10 1:50
memberSteven Kirk11-Aug-10 1:50 
GeneralExactly what I was looking for! Pin
Collin Jasnoch11-Feb-10 10:40
memberCollin Jasnoch11-Feb-10 10:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150624.2 | Last Updated 7 Nov 2009
Article Copyright 2009 by Steven Kirk
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid