Click here to Skip to main content
Click here to Skip to main content

DataGrid with Movable Rows

, 8 Oct 2009
Rate this:
Please Sign up or sign in to vote.
The DataGridMovableRows control lets you move rows around in a DataGrid

Introduction

The DataGridMovableRows control lets you move rows around in a DataGrid! We created it for our Gantt control implementation and decided to share it with the community.

The DataGridMovableRows control (deriving from DataGrid) allows the end user to select rows and simply drag them around to a new location. A visual drag cue is provided when the user moves the mouse over the row header of the selected row and visual cues are also provided to indicate drop location.

BeforeMovingRows and RowsMoved events are fired. RowsMoved will tell you which rows are being moved and to what new location. You could typically update your bound list to reflect this change, in this event handler.

Background

Our Silverlight Gantt control required a DataGrid with support for movable rows. This obviously was not supported internally by the DataGrid and so we had to implement it ourselves. This ended up being a non-trivial task due to customized scrolling behavior implemented in the DataGrid. As the grid is scrolled vertically, the top rows that are going out of view are actually getting hidden, rather than simply being scrolled out. This makes it very hard to determine the co-ordinates of a row so that the drag-cue and drop-cue can be rendered properly.

We created a new control DataGridMovableRows which encapsulates all the tracking details and presents you two simple event handlers as mentioned above, BeforeMovingRows and RowsMoved.

Note that the only way to persist the order of items in a table/list is to include a separate field, for example "SortOrder". This field should be updated accordingly as the user drags the rows around in a DataGrid. The attached sample uses this approach to persist the new order. This also means that before binding your table/list to the DataGrid, make sure to sort it by this "SortOrder" field.

Using the Code

To begin with, listen to the BeforeMovingRows event handler where you can optionally cancel the move based on what rows are selected. Then make the selected rows contiguous, the built-in logic does not support moving rows that are not adjacent, so this step is necessary.

private void dataGrid1_BeforeMovingRows
	(object sender, System.ComponentModel.CancelEventArgs e)
{ // If the selected includes the first row, cancel the selection.
if (this.dataGrid1.SelectedItems.Contains(this.firstItem))
{ e.Cancel = true; return; }
// Make selected items contiguous.
this.FlattenSelection(); }

// If the user selected row 2 and row 5, then this method will also select row 3 and 4.
// This is necessary because the logic here assumes that all selected objects are
// adjacent to each other.
private void FlattenSelection()
{ int topRowIndex = Int32.MaxValue; int botRowIndex =Int32.MinValue; 
IList<CustomObject> list = this.dataGrid1.ItemsSource as IList<CustomObject>;
foreach (CustomObject item in this.dataGrid1.SelectedItems) 
		{ int index = list.IndexOf(item);
if (index < topRowIndex) topRowIndex = index; 
if (index > botRowIndex) botRowIndex = index; }
if (this.dataGrid1.SelectedItems.Count < (botRowIndex - topRowIndex + 1))
{ for (int i = topRowIndex; i <= botRowIndex; i++)
{ CustomObject o = list[i]; 
if (this.dataGrid1.SelectedItems.Contains(o)== false) 
	this.dataGrid1.SelectedItems.Add(o); } } }

Then listen to the RowsMoved event handler where you can adjust the order of the items as follows:

void dataGrid1_RowsMoved(object sender, RowsMovedEventArgs args)
{ // args.StartIndex - The start index of the set of rows that are being moved
// args.Count - The number of adjacent rows below the start index that are being moved.
// args.DestinationIndex - The destination for this move
// Interpreting this move varies by the application.
// Here we will adjust the SortOrder of the bound objects and 
// then rebind them with the grid.
IList<CustomObject> list = this.dataGrid1.ItemsSource as IList<CustomObject>;
this.MoveInList(list, args.StartIndex, args.Count, args.DestinationIndex); }

// There are 2 ways to handle this:
// 1) Move items and adjust their SortOrder (this is the technique used here).
// 2) Another option is to just adjust the SortOrder 
// and then rebind the DataGrid with a new list
// that's properly sorted based on SortOrder.
public int MoveInList(IList<CustomObject> list, int start, int count, int dest) 
{ int from; int to; int newDestOfStart; 
if (dest > start) { from = start; to = dest - 1; 
for (int i = 0; i < count; i++) { CustomObject view = list[start]; 
list.RemoveAt(start); list.Insert(dest - 1, view); 
} 
newDestOfStart = dest - count; } 
else 
{ from = dest; to = start + count - 1; 
for (int i = 0; i < count; i++) 
{ CustomObject view = list[start + i]; 
list.RemoveAt(start + i); list.Insert(dest + i, view); } 
newDestOfStart = dest; } for (int i = from; i <= to; i++) 
{ ((CustomObject)list[i]).SortOrder = i; } 
return newDestOfStart; }

Points of Interest

We understand that being able to drag and drop rows from the grid into other controls is another useful scenario. If you are interested in this, please update the comments section and we will create a new article for this.

History

  • 7th October, 2009: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

RadiantQ
Product Manager RadiantQ
United States United States
No Biography provided

Comments and Discussions

 
QuestionJust what I needed! PinmemberGreg Lindberg15-Apr-13 6:56 
QuestionNo support for row detail template PinmemberMember 94546543-Oct-12 4:47 
GeneralAbout 'Ctrl' multiple selected, and some bug. Pinmemberpageup0084-Jun-12 23:01 
QuestionHow to increase row height? Pinmemberrj_sp28-Mar-12 2:09 
AnswerRe: How to increase row height? Pinmemberkajalpatel15-Nov-12 2:57 
GeneralHelp Pinmembernikhil123425-Nov-10 2:15 
GeneralGood article. Have some issues Pinmemberzorrack1-Nov-10 5:46 
GeneralThanks for posting this PinmemberRay Loveless21-Sep-10 6:43 
GeneralGood feature which is not provided in silverlight sdk [modified] Pinmembershital@meenu24-Aug-10 20:36 
GeneralThis should be stantard PinmemberLuc Archambault7-Feb-10 8:04 
GeneralGood Keep going PinmemberErnesto Tejeda8-Oct-09 6:27 

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 | Mobile
Web04 | 2.8.140721.1 | Last Updated 8 Oct 2009
Article Copyright 2009 by RadiantQ
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid