WPF 4 DataGrid Row Drag and Drop

Posted by: Mahesh Sabnis , on 3/29/2011, in Category WPF
Views: 124375
Abstract: The WPF DataGrid control has lots of features for data representations and manipulations (like row column drag drop). One of the nicest features of the DataGrid, is that we can change the column position using Drag-Drop. In this article, we will see how to implement Drag and Drop in a DataGrid Row.

I recently had a discussion with a colleague about the capabilities of WPF for application development. We had discussions on the various new features in WPF including the capabilities of the WPF DataGrid control. The WPF DataGrid control has lots of features for data representations and manipulation. One of the nicest features of the DataGrid, is that we can change the column position using Drag-Drop. When my colleague asked me if the Drag-Drop effect is possible for the DataGridRow too, I was clueless. But this question gave me enough motivation to try my hands on implementing a Drag drop with the DataGridRow. This article demonstrates how to do so.

Step 1: Open VS2010 and create a WPF windows application. Name it as ‘WPF40_DataGrid_Row_Drag_Drop’.

Step 2: To this project, add a new class file and name it as ‘DataAccess.cs’. Write the following code in it:  

wpf data access

The above class, defines classes for Employee Entity and the EmployeeCollection, to store Employee records.

Step 3: Open MainWindow.Xaml and define an instance for the ‘EmployeeCollection’ class in Windows.Resource. Also define the DataGrid columns and set the AllowDrop property of the DataGrid to ‘true’. This will enable Drag-Drop operations on the DataGrid control.  

wpf-drag-drop 

Step 4: Now we need to write some code which will provide the DataGridRow Drag-Drop functionality. To do so, open MainWindow.xaml.cs and define a delegate. This delegate will return the position of the Mouse Button event and Drag-Drop event. This delegate accepts an ‘IInputElement’ interface object, which is used to establish the common event and event related properties and methods for WPF element input processing. Here the input is sent using a Mouse button. The delegate is declared at the namespace level as shown below:

wpf-dragdrop-delegate

After declaring the delegate, we now need to check if the Mouse is placed on the DataGridRow for Drag-Drop operation. To do this, a method is written which returns Boolean and accepts two parameters - the first parameter is the ‘Visual’ object which provides rendering to the WPF application and the second parameter is the ‘GetDragDropPosition’ delegate. This method provides logic for capturing the Rectangle ‘Rect’ information, within which the rendering of the Drag-Drop operations is managed using ‘Point’ object, which is provided by the Visual object. So if the ‘Rect’ contains the specified point for Drag-Drop, the method returns true. Here’s the code for this method:

wpf-point-capture

Now we need to get the DataGridRow for Drag-Drop. The method is as shown below:

wpf-datagrid-row

Now it’s time for us to define the logic for getting the Drag-Drop index for the DataGridRow. To do so, we need to iterate through the ‘Items’ property of the DataGrid, then retrieve the DataGridRow for the specific index and check whether it is on the Mouse Target with its Rect position, which we defined earlier using ‘IsTheMouseOnTarget’ method 

 wpf-datagrid-rowindex

Now declare the class level variable for keeping track of the DaraGridRow object index:

int prevRowIndex = -1;

After following the above steps, we now need to implement ’PreviewMouseLeftButtonDown’ event of DataGrid, which will get the Employee object on the selected index and will provide the Drag-Drop effect. The code for the same is as shown below:

wpf-preview-mouseleft 

Step 5: Let us now implement the drop event of the DataGrid. This will track the Drop index, so once the drop operation is completed, the Row will be removed from the previous index and will be inserted at a new index.

wpf-drop-event

Finally just hook these events in the constructor, as shown below:

wpf-register-events 

Step 6: That’s it! Run the application, drag a Row from the DataGrid and drop it at a new index. Note: WPF DataGrid always shows the last row which is empty. This row is used for Insert operation in the DataGrid, so the Drag-Drop is not applicable there and we have checked this is in the Drop event. Output, when the screen loads:

wpf-employee-demo

After Drag-Drop: Employee No. 4 is dropped to position 2.

wpf-dragdrop-demo

and here’s the error message if you try to drop a row in the last row:

wpf-dragdrop-error  

Conclusion: In this article, we saw how to implement Drag-Drop effect for the WPF DataGridRow. The entire source code of this article can be downloaded over here

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by AMR on Friday, June 24, 2011 3:22 AM
Congratulations Mahesh ,

It's a very helpfull article.
I was just wondering to know if i can use this code in my project?
Thank you
Comment posted by Teja on Wednesday, July 11, 2012 1:49 PM
Thank you! This tutorial was very useful to me!
Comment posted by simon on Tuesday, July 31, 2012 1:40 PM
Thanks for this article. But, drag and drop does NOT work after the grid has been sorted.
Could you please explain why?
Thanks and looking forward to your feedbacks...
Comment posted by fraternityleave on Thursday, September 6, 2012 12:32 PM
Thanks a lot for the examples. just what I was looking for.
Comment posted by Jeffrey on Monday, November 26, 2012 10:46 AM
Not work if there are many rows and columns, and the scroll bar cannot function.
Comment posted by CaffeineMachine on Thursday, January 31, 2013 2:55 PM
Thanks for the article, Mahesh. It was very helpful.

I think if you try to drag a row outside the bounds of the datagrid (for scrolling), it will throw an exception in the IsMouseOnTargetRow method, where the VisualTreeHelper.GetDescendantBounds call fails. This may be what Jeffrey was referring to.
Comment posted by Sven Turowski on Tuesday, July 9, 2013 1:32 AM
The article is extremly helpful!
Thanks a lot!!

Sven
Comment posted by cheshire cat on Wednesday, October 23, 2013 6:21 PM
doesn't work with comboboxes: it doesn't select the items...
Comment posted by Faiyaz Khan on Monday, June 30, 2014 10:47 PM
Good article, I used it in my recent development. Additionally if want grid  to scroll up and down please use below code.

var gridHeight = dgEmployee.ActualHeight;
if (p.Y > (gridHeight - 20))
{
    ScrollViewer scrollViewer = FindChild<ScrollViewer>(dgEmployee, "DG_ScrollViewer");
    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 1);
}
if (p.Y < 20)
{
    ScrollViewer scrollViewer = FindChild<ScrollViewer>(dgEmployee, "DG_ScrollViewer");
    if(scrollViewer.VerticalOffset > 1)
        scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 1);
}