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 (this.dataGrid1.SelectedItems.Contains(this.firstItem))
{ e.Cancel = true; return; }
this.FlattenSelection(); }
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)
{
IList<CustomObject> list = this.dataGrid1.ItemsSource as IList<CustomObject>;
this.MoveInList(list, args.StartIndex, args.Count, args.DestinationIndex); }
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
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.