a·gen·tic a·gil·i·ty

Wpf Drag & Drop behaviour

Explains how to implement flexible drag and drop in WPF using MVVM, with customisable drop behaviour and bindable options for ItemsControls, including code examples.

Published on
5 minute read
Image
https://nkdagility.com/resources/-BCzcrYA0j8
Subscribe

A colleague of mine was having a bit of trouble getting drag and drop working in a way that fitted well with the MVVM pattern. This is really quite simple once you have a certain level of understanding of Patterns, but is a complete nightmare if you do not.

One of the founding principals of MVVM is that you should never be writing code in your code behind, it should all be encapsulated away and be bindable in XAML to achieve the result. Anyone who has tackled drag and drip will have suddenly found their code behind covered in code for handling both the drag and the drop, and multiplied up when dealing with multiple controls.

I cruised the web for information, of which I found plenty and settled on an example by Bea Stollnitz of Microsoft. In her post i had found one of the best and most intuitive examples of the Drag & Drop Behaviour written in C#.

I am not going to go into all of her code which she has available for download, just to say that it is nice, and is exactly what I am looking for even with the limitations that she described.

The functionality available allows you to drag a piece of data from one ItemsControl to another of the same data type or to reorder within itself. It provides for a floating template for the dragging item and a visual cue for the drop location.

Wpf Drag & Drop behaviour

I wanted to augment this to allow for other scenarios while keeping as much functionality as possible.

Likes:

Dislikes:

My version lets you inject additional functionality at runtime. The adjusted class diagram shows the relationships, but we only really use the DragDropBehaviour class

Wpf Drag & Drop behaviour  

You can still use the standard options:

 1<DockPanel>
 2    <Label DockPanel.Dock="Top"  Content="Checkout" />
 3    <ListBox     hlb:DragDropBehaviour.IsDragSource="true"
 4                 hlb:DragDropBehaviour.IsDropTarget="true"
 5                 hlb:DragDropBehaviour.DragTemplate="{StaticResource MyTemplate}"
 6                 ItemsSource="{Binding Items}"
 7                 MinWidth="100"
 8                 MinHeight="100"
 9                 AllowDrop="True"
10                 SelectionMode="Multiple">
11    </ListBox>
12</DockPanel>

But I have added another bindable option of DropProcessor that allows you to override the default DropProcessor to achieve whatever you want.

1<ListBox hlb:DragDropBehaviour.DropProcessor="{Binding DropProcessor}"
2    hlb:DragDropBehaviour.IsDragSource="true"
3    hlb:DragDropBehaviour.IsDropTarget="true"
4    hlb:DragDropBehaviour.DragTemplate="{StaticResource moo}"
5    ItemsSource="{Binding Items}"
6    MinWidth="100"
7    MinHeight="100">

In this example I have created a little gun shop called “Nutters R’ Us” where you can buy weapons and ordinance. You can see that there is an area for weapons, and area for ordinance and an area for your selected purchases.

Wpf Drag & Drop behaviour

I have added a custom DropProcessor only to the Checkout area that only applies when you drop items of type “OrdinanceViewModel”

 1Public Class CheckoutDropProcessor
 2    Inherits DropProcessor
 3
 4    Public Overrides Function GetDropAdorner(ByVal behaviour As DragDropBehaviour, ByVal adornerLayer As System.Windows.Documents.AdornerLayer) As DropAdorner
 5        If TypeOf behaviour.TargetItemContainer.DataContext Is WeaponViewModel Then
 6            If TypeOf behaviour.SourceItemContainer.DataContext Is OrdnanceViewModel Then
 7                Return New OrdnanceToWeaponDropAdorner(behaviour, adornerLayer)
 8            End If
 9        End If
10        Return MyBase.GetDropAdorner(behaviour, adornerLayer)
11    End Function
12
13    Public Overrides Function IsDropAllowed(ByVal behaviour As DragDropBehaviour, ByVal draggedItem As Object) As Boolean
14        If Not behaviour.SourceItemContainer Is Nothing AndAlso TypeOf behaviour.SourceItemContainer.DataContext Is OrdnanceViewModel Then
15            If Not behaviour.TargetItemContainer Is Nothing AndAlso TypeOf behaviour.TargetItemContainer.DataContext Is WeaponViewModel Then
16                Return True
17            End If
18            Return False
19        End If
20        Return MyBase.IsDropAllowed(behaviour, draggedItem)
21    End Function
22
23    Public Overrides Sub Drop(ByVal behaviour As DragDropBehaviour, ByVal draggedItem As Object, ByVal dropEffect As System.Windows.DragDropEffects)
24        If Not behaviour.TargetItemContainer Is Nothing AndAlso TypeOf behaviour.TargetItemContainer.DataContext Is WeaponViewModel Then
25            If TypeOf behaviour.SourceItemContainer.DataContext Is OrdnanceViewModel Then
26                CType(behaviour.TargetItemContainer.DataContext, WeaponViewModel).AddOrdinance(CType(behaviour.SourceItemContainer.DataContext, OrdnanceViewModel))
27                Dim indexRemoved As Integer = -1
28                If ((dropEffect And DragDropEffects.Move) <> DragDropEffects.None) Then
29                    indexRemoved = Utilities.RemoveItemFromItemsControl(behaviour.SourceItemsControl, draggedItem)
30                End If
31                If (((indexRemoved <> -1) AndAlso (behaviour.SourceItemsControl Is behaviour.TargetItemsControl)) AndAlso (indexRemoved < behaviour.InsertionIndex)) Then
32                    behaviour.InsertionIndex -= 1
33                End If
34                Exit Sub
35            End If
36        End If
37        MyBase.Drop(behaviour, draggedItem, dropEffect)
38
39    End Sub
40
41End Class

Wpf Drag & Drop behaviour

This class inherits from the base class “DropProcessor” that provides the same functionality as the original article, but I have

overridden couple of methods. The first, “GetDropAdorner” test to make sure that you are dropping a OrdinanceViewModel onto a WeaponViewModel and provides a different and custom DropAdorner that instead of providing the lovely insertion visual it just applied a “IsDropTarget” property to the ListBoxItem to allow a template to control the visual. The IsAllowedDrop also test for this case, as does the Drop method. In all cases they are just testing for a special case of Drop and call the base classes methods.

The diagram for the demo app is a little large, but you can see how much I still suck at MVVM, and although I have learned a lot doing this demo, I am still tempted to share ViewModels… but that is a bad habit.

Wpf Drag & Drop behaviour

I have highlighted the two main classes, and we have already discussed the CheckoutDropProcessor. This allows you the flexibility to augment your drop scenarios without all of your developers having to get too deep in the guts on the behaviour, thus leaving them plenty of time for the real work of actually building something useful.

I have put this up on Codeplex , and both the source and binaries are available.

Technorati Tags: .NET   WPF   CodeProject   MVVM   Silverlight

Software Development
Subscribe

Related Blog

No related videos found.

Connect with Martin Hinshelwood

If you've made it this far, it's worth connecting with our principal consultant and coach, Martin Hinshelwood, for a 30-minute 'ask me anything' call.

Our Happy Clients​

We partner with businesses across diverse industries, including finance, insurance, healthcare, pharmaceuticals, technology, engineering, transportation, hospitality, entertainment, legal, government, and military sectors.​

YearUp.org Logo

YearUp.org

Cognizant Microsoft Business Group (MBG) Logo

Cognizant Microsoft Business Group (MBG)

New Signature Logo

New Signature

Teleplan Logo

Teleplan

Xceptor - Process and Data Automation Logo

Xceptor - Process and Data Automation

Graham & Brown Logo

Graham & Brown

NIT A/S

Slicedbread Logo

Slicedbread

Milliman Logo

Milliman

Hubtel Ghana Logo

Hubtel Ghana

Brandes Investment Partners L.P. Logo

Brandes Investment Partners L.P.

Sage Logo

Sage

Big Data for Humans Logo

Big Data for Humans

Kongsberg Maritime Logo

Kongsberg Maritime

Jack Links Logo

Jack Links

Deliotte Logo

Deliotte

Emerson Process Management Logo

Emerson Process Management

SuperControl Logo

SuperControl

Nottingham County Council Logo

Nottingham County Council

New Hampshire Supreme Court Logo

New Hampshire Supreme Court

Department of Work and Pensions (UK) Logo

Department of Work and Pensions (UK)

Ghana Police Service Logo

Ghana Police Service

Washington Department of Enterprise Services Logo

Washington Department of Enterprise Services

Washington Department of Transport Logo

Washington Department of Transport

Slaughter and May Logo

Slaughter and May

YearUp.org Logo

YearUp.org

Boeing Logo

Boeing

Emerson Process Management Logo

Emerson Process Management

Freadom Logo

Freadom

Healthgrades Logo

Healthgrades