Get in touch
Thank you
We will get back to you as soon as possible

26.2.2010

5 min read

WPF Software Development. Model-View Application. Drag and Drop.

Imagine you have two or more data bound (or not data bound) ItemsControls in the same Window. You may want to drag an item from an ItemsControl and drop it on another one. Or maybe you want to drag and drop it in a different position within the same ItemsControl. This article from series of articles about using MVVM pattern in WPF/Silverlight technology explains how to add “drag and drop” functionality to WPF MVVM application for few ItemsControls.

A few days ago I wanted to do “drag and drop” functionality (there is a lot of information about this in the Internet) but in MVVM we can’t use events in code-behind. So let’s try to get without it  - we are used to various tricky tasks here, as, as you probably already know,  Binary Studio has already accomplished several significant projects in sphere of wpf software development outsourcing.

WPF MVVM application

Imagine you have two or more data bound (or not data bound) ItemsControls in the same Window. You may want to drag an item from an ItemsControl and drop it on another one. Or maybe you want to drag and drop it in a different position within the same ItemsControl. In the end of this article we’ll able to do it in WPF MVVM application.

But before beginning I want to tell you about a very interesting Bea Stollnitz blog. It’s definitely the best blog about WPF/Silverlight technology I’ve ever seen. Bea Stollnitz has worked at Microsoft for five years, helping to create the Silverlight and WPF application frameworks. She focused mostly on data binding, controls, and styles. So it is there, that I’ve found a post about drag and drop. I won’t go into any details about implementation (it’s really good code), I just want to tell how we can use it in our projects with those class.

Let’s start. First of all we should copy four files from the project at the end of her post – DraggedAdorner.cs, InsertionAdorner.cs, DragDropHelper.cs and Utilities.cs. In my project it looks like this:

Drag and drop in WPF MVVM using DraggedAdorner.cs, InsertionAdorner.cs, DragDropHelper.cs and Utilities.cs.

(of course we should change namespaces).

After this, within your app, you simply need to add three attached properties:

  • IsDropTarget should be set on the ItemsControl that you want to drag items to. This property is of type boolean and should be set to true.
  • IsDragSource should be set on the ItemsControl that you want to drag items from. This property should also be set to true.
  • DragDropTemplate should also be set on the drag source ItemsControl (where you want to drag the items from). This property should be set to a DataTemplate that controls how the data item should be displayed while it is dragged around.

And that’s all there is to it.

In my application I wrote very simple products list with cart (customer can just drag and grop goods from product list to cart. I didn’t make deleting goods and other features – it’s not a goal of this article.) So MainView.xaml looks like:

<Grid ScrollViewer.VerticalScrollBarVisibility="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Add additional content here -->
<Border Grid.Column="0" BorderBrush="Gray" BorderThickness="1" Margin="10, 10,30,10" >
<Border.BitmapEffect>
<BitmapEffectGroup>
<DropShadowBitmapEffect Color="Black" Direction="10"
ShadowDepth="15" Softness="1" Opacity="0.5"/>
</BitmapEffectGroup>
</Border.BitmapEffect>
<StackPanel>
<Label>Goods</Label>
<ItemsControl Background="AliceBlue" ItemsSource="{Binding Path=Goods}"
ItemTemplate="{StaticResource goodsTemplate}"
ItemsPanel="{StaticResource panelTemplate}" Margin="0,0,30,0"
BLL:DragDropHelper.IsDragSource="true" BLL:DragDropHelper.IsDropTarget="false"
BLL:DragDropHelper.DragDropTemplate="{StaticResource productTemplateDrag}"/>
</StackPanel>
</Border>

<Border Grid.Column="1" BorderBrush="Gray" BorderThickness="1" Margin="10, 10,30,10" >
<Border.BitmapEffect>
<BitmapEffectGroup>
<DropShadowBitmapEffect Color="Black" Direction="20"
ShadowDepth="5" Softness="1" Opacity="0.5"/>
</BitmapEffectGroup>
</Border.BitmapEffect>
<StackPanel >
<Label>Cart</Label>
<ListView ItemsSource="{Binding Path=Cart}" Height="480"
BLL:DragDropHelper.IsDragSource="true"
BLL:DragDropHelper.IsDropTarget="true"
BLL:DragDropHelper.DragDropTemplate="{StaticResource productTemplateDrag}"
ItemTemplate="{StaticResource cartTemplate}">
</ListView>
<StackPanel Orientation="Horizontal">
<Label>Total price:</Label><Label Content="{Binding Path=Total}"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>

And MainViewModel.cs is:

#region [ Public properties ] 
public List<Product> Goods { get; set; }
public ObservableCollection<Product> Cart { get; set; }
private double _total;
public double Total
        { 
get 
            { 
return _total; 
            } 
set 
            { 
if(value!=null)
                { 
                    _total = value; 
                    OnPropertyChanged("Total"); 
                } 
            } 

        } 
#endregion 

#region [ Constructor ] 
public MainViewModel() 
        { 
            Cart = new ObservableCollection<Product>(); 
            Cart.CollectionChanged += Cart_CollectionChanged; 

            Goods = new List<Product>(); 
foreach (Product good in DataModel.GetData())
                Goods.Add(good); 
        } 
void Cart_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        { 
            Total = Cart.Sum(p => p.Price); 
        } 
#endregion

That’s all! As a result we have:

Img12

and it works like:

Img13

As you can notice, the template which we made for dragged items and total price is changed too. At the end I’ll write features and limitations as it was written by Bea. If you want to use not only ItemsControl or other panel you should just add more “if” to her code.

Here is the list of features and limitations of this solution.

WPF Features

  • The code in this sample enables the user to drag and drop between ItemsControls and any controls that derive from it (see exception for TreeView in the limitations section).
  • This solution supports dragging and dropping within the same ItemsControl.
  • This solution supports dragging and dropping between non data bound and data bound ItemsControls.
  • I’ve added support for ItemsControls that use FlowPanel and StackPanel (with both horizontal and vertical orientation). Support for other panels can be added easily.
  • This sample prevents the user from dropping a data item into a target ItemsControl when its data items are of an incompatible type. For example, if the drag source ItemsControl contains a collection of Potatoes but the drop target ItemsControl is data bound to a collection of Squirrels, the app will prevent the user from doing the drop.
  • This sample provides visual feedback of where the dragged item will go if dropped. For example, when dragging a data item over a ListBox, this sample shows a horizontal line between the two items where the item will go if dropped.

WPF Limitations

  • This solution doesn’t drag and drop data items across Windows.
  • It also doesn’t work across Applications.
  • It allows drag and drop to work between ItemsControls, but it does not allow you to drag or drop to a ContentControl.
  • This sample works as expected for the first level of a TreeView, but not for nested levels of the hierarchy.

So we’ve got what we want: “drag and drop” in WPF MVVM application. Hope it is of some help to you! (Here is source code of my project.)

Artyom G., .NET team, Binary Studio

Thank you
We will get back to you as soon as possible

Looking for a tech partner to help you scale your project?

Let’s schedule a quick call to explore how we can support your business objectives.

Christina Berko

Let’s schedule a quick call to explore how we can support your business objectives.

Christina Berko

Client Manager

0 Comments
name *
email *

Featured Case Studies