# Rows Reordering in Self-reference Hierarchy

Consider the case you have a bound **RadGridView** with self-reference hierarchical data. This help article demonstrates how to utilize the [RadGridViewDragDropService](https://www.telerik.com/products/winforms/documentation/controls/gridview/features/drag-and-drop/radgridviewdragdropservice) and implement rows reordering.

> caption Figure 1: Rows reordering in self-reference hierarchy

![WinForms RadGridView Rows Reordering Self-Reference Hierarchy](https://www.telerik.com/products/winforms/documentation/assets/ed14518b1eb87af0535a2ea293f9f342/gridview-drag-and-drop-rows-reordering-in-self-reference-hierarchy001.gif)

1\. Populate **RadGridView** with self-reference hierarchical data:

```C#

DataTable dt;

private void RadForm_Load(object sender, EventArgs e)
{
    dt = new DataTable();
    dt.Columns.Add("Id");
    dt.Columns.Add("Name");
    dt.Columns.Add("ParentId");
    FillData();
}

private void FillData()
{
    this.radGridView1.Relations.AddSelfReference(this.radGridView1.MasterTemplate, "Id", "ParentId");

    for (int i = 1; i <= 3; i++)
    {
        dt.Rows.Add(i, "Parent" + i, 0);
        for (int j = 4; j <= 9; j++)
        {
            int childIndex = ((i - 1) * 9 + j + i);
            dt.Rows.Add(childIndex, "Child" + childIndex, i);
        }
    }
    this.radGridView1.DataSource = dt;
}

```

```VB.NET
Private dt As DataTable

Private Sub RadForm_Load(ByVal sender As Object, ByVal e As EventArgs)
    dt = New DataTable()
    dt.Columns.Add("Id")
    dt.Columns.Add("Name")
    dt.Columns.Add("ParentId")
    FillData()
End Sub

Private Sub FillData()
    Me.radGridView1.Relations.AddSelfReference(Me.radGridView1.MasterTemplate, "Id", "ParentId")
    For i As Integer = 1 To 3
        dt.Rows.Add(i, "Parent" & i, 0)
        For j As Integer = 4 To 9
            Dim childIndex As Integer = ((i - 1) * 9 + j + i)
            dt.Rows.Add(childIndex, "Child" & childIndex, i)
        Next
    Next

    Me.radGridView1.DataSource = dt
End Sub
```

2\. Register a custom [GridHierarchyRowBehavior](https://www.telerik.com/products/winforms/documentation/controls/gridview/visual-elements/rows/row-behaviors)	which starts the [RadGridViewDragDropService](https://www.telerik.com/products/winforms/documentation/controls/gridview/features/drag-and-drop/radgridviewdragdropservice) when you click with the left mouse button:

#### Register the custom row behavior

```C#

    BaseGridBehavior gridBehavior = this.radGridView1.GridBehavior as BaseGridBehavior;
    gridBehavior.UnregisterBehavior(typeof(GridViewHierarchyRowInfo));
    gridBehavior.RegisterBehavior(typeof(GridViewHierarchyRowInfo), new RowSelectionGridBehavior());

```

```VB.NET

Dim gridBehavior As BaseGridBehavior = TryCast(Me.radGridView1.GridBehavior, BaseGridBehavior)
gridBehavior.UnregisterBehavior(GetType(GridViewHierarchyRowInfo))
gridBehavior.RegisterBehavior(GetType(GridViewHierarchyRowInfo), New RowSelectionGridBehavior())

```

Override the **OnMouseDownLeft** method of the **GridHierarchyRowBehavior** and start the service:

```C#

public class RowSelectionGridBehavior : GridHierarchyRowBehavior
{
    protected override bool OnMouseDownLeft(MouseEventArgs e)
    {
        GridDataRowElement row = this.GetRowAtPoint(e.Location) as GridDataRowElement;
        if (row != null)
        {
            RadGridViewDragDropService svc = this.GridViewElement.GetService<RadGridViewDragDropService>();
            svc.Start(new SnapshotDragItem(row));
        }
        return base.OnMouseDownLeft(e);
    }
}

```

```VB.NET
Public Class RowSelectionGridBehavior
    Inherits GridHierarchyRowBehavior

    Protected Overrides Function OnMouseDownLeft(ByVal e As MouseEventArgs) As Boolean
        Dim row As GridDataRowElement = TryCast(Me.GetRowAtPoint(e.Location), GridDataRowElement)
        If row IsNot Nothing Then
            Dim svc As RadGridViewDragDropService = Me.GridViewElement.GetService(Of RadGridViewDragDropService)()
            svc.Start(New SnapshotDragItem(row))
        End If

        Return MyBase.OnMouseDownLeft(e)
    End Function
End Class
```

3\. Handle the RadDragDropService.**PreviewDragStart** event in order to indicate that **RadGridView** can start the drag operation. In the RadDragDropService.**PreviewDragOver** event you can control on what targets the row being dragged can be dropped on. In the **PreviewDragDrop** event you can perform the actual reordering of the data bound records. Note that it is important to update the **ParentId** field of the affected record. Thus, you will indicate the new parent record to which the dragged record belongs.

```C#

private void SubscribeToDragDropEvents()
{
    RadDragDropService svc = this.radGridView1.GridViewElement.GetService<RadDragDropService>();
    svc.PreviewDragStart += svc_PreviewDragStart;
    svc.PreviewDragOver += svc_PreviewDragOver;
    svc.PreviewDragDrop += svc_PreviewDragDrop;
}

GridViewRowInfo draggedDataRow = null;
private void svc_PreviewDragStart(object sender, PreviewDragStartEventArgs e)
{
    SnapshotDragItem draggedSnapshot = e.DragInstance as SnapshotDragItem;
    GridDataRowElement draggedRowElement = draggedSnapshot.Item as GridDataRowElement;
    draggedDataRow = draggedRowElement.RowInfo;
    e.CanStart = true;
}

private void svc_PreviewDragOver(object sender, RadDragOverEventArgs e)
{
    SnapshotDragItem draggedSnapshot = e.DragInstance as SnapshotDragItem;
   
    if (draggedSnapshot == null)
    {
        e.CanDrop = false;
        return;
    }
    GridDataRowElement draggedRowElement = draggedSnapshot.Item as GridDataRowElement;
    if (draggedRowElement==null)
    {
        e.CanDrop = false;
        return;
    }
    e.CanDrop = true;
    draggedRowElement.Visibility = ElementVisibility.Hidden;
}

private void svc_PreviewDragDrop(object sender, RadDropEventArgs e)
{
    SnapshotDragItem draggedSnapshot = e.DragInstance as SnapshotDragItem;
    if (draggedSnapshot == null)
    {
        return;
    }
    GridDataRowElement draggedRowElement = draggedSnapshot.Item  as GridDataRowElement;
    GridDataRowElement targetRowElement = e.HitTarget as GridDataRowElement;

    if (draggedRowElement == null)
    {
        return;
    }
    DataRowView sourceRowView = draggedDataRow.DataBoundItem as DataRowView;
    DataRowView targetRowView = targetRowElement.RowInfo.DataBoundItem as DataRowView;
    if (!(targetRowElement.RowInfo.Cells["ParentId"].Equals(draggedRowElement.RowInfo.Cells["ParentId"])))
    {
        e.Handled = true;
        int targetIndex = dt.Rows.IndexOf(targetRowView.Row);

        DataRow newRow = dt.NewRow();
        newRow["ParentId"] = targetRowView.Row["ParentId"];
        newRow["Name"] = sourceRowView.Row["Name"];
        newRow["Id"] = sourceRowView.Row["Id"];
        dt.Rows.Remove(sourceRowView.Row);
        dt.Rows.InsertAt(newRow, targetIndex);
    }
}

```

```VB.NET

Private Sub SubscribeToDragDropEvents()
    Dim svc As RadDragDropService = Me.radGridView1.GridViewElement.GetService(Of RadDragDropService)()
    AddHandler svc.PreviewDragStart, AddressOf svc_PreviewDragStart
    AddHandler svc.PreviewDragOver, AddressOf svc_PreviewDragOver
    AddHandler svc.PreviewDragDrop, AddressOf svc_PreviewDragDrop
End Sub

Private draggedDataRow As GridViewRowInfo = Nothing
Private Sub svc_PreviewDragStart(ByVal sender As Object, ByVal e As PreviewDragStartEventArgs)
    Dim draggedSnapshot As SnapshotDragItem = TryCast(e.DragInstance, SnapshotDragItem)
    Dim draggedRowElement As GridDataRowElement = TryCast(draggedSnapshot.Item, GridDataRowElement)
    draggedDataRow = draggedRowElement.RowInfo
    e.CanStart = True
End Sub

Private Sub svc_PreviewDragOver(ByVal sender As Object, ByVal e As RadDragOverEventArgs)
    Dim draggedSnapshot As SnapshotDragItem = TryCast(e.DragInstance, SnapshotDragItem)

    If draggedSnapshot Is Nothing Then
        e.CanDrop = False
        Return
    End If

    Dim draggedRowElement As GridDataRowElement = TryCast(draggedSnapshot.Item, GridDataRowElement)

    If draggedRowElement Is Nothing Then
        e.CanDrop = False
        Return
    End If

    e.CanDrop = True
    draggedRowElement.Visibility = ElementVisibility.Hidden
End Sub

Private Sub svc_PreviewDragDrop(ByVal sender As Object, ByVal e As RadDropEventArgs)
    Dim draggedSnapshot As SnapshotDragItem = TryCast(e.DragInstance, SnapshotDragItem)

    If draggedSnapshot Is Nothing Then
        Return
    End If
    Dim draggedRowElement As GridDataRowElement = TryCast(draggedSnapshot.Item, GridDataRowElement)
    Dim targetRowElement As GridDataRowElement = TryCast(e.HitTarget, GridDataRowElement)
    If draggedRowElement Is Nothing Then
        Return
    End If

    Dim sourceRowView As DataRowView = TryCast(draggedDataRow.DataBoundItem, DataRowView)
    Dim targetRowView As DataRowView = TryCast(targetRowElement.RowInfo.DataBoundItem, DataRowView)
    If Not (targetRowElement.RowInfo.Cells("ParentId").Equals(draggedRowElement.RowInfo.Cells("ParentId"))) Then
        e.Handled = True
        Dim targetIndex As Integer = dt.Rows.IndexOf(targetRowView.Row)
        Dim newRow As DataRow = dt.NewRow()
        newRow("ParentId") = targetRowView.Row("ParentId")
        newRow("Name") = sourceRowView.Row("Name")
        newRow("Id") = sourceRowView.Row("Id")
        dt.Rows.Remove(sourceRowView.Row)
        dt.Rows.InsertAt(newRow, targetIndex)
    End If
End Sub
```

## See Also

* [RadGridViewDragDropService](https://www.telerik.com/products/winforms/documentation/controls/gridview/features/drag-and-drop/radgridviewdragdropservice)
* [RadDragDropService](https://www.telerik.com/products/winforms/documentation/telerik-presentation-framework/raddragdropservice)
* [Rows >> Drag and Drop](https://www.telerik.com/products/winforms/documentation/controls/gridview/visual-elements/rows/drag-and-drop)
* [How to reorder rows in bound RadGridView](https://www.telerik.com/products/winforms/documentation/knowledge-base/gridview-drag-drop-bound-mode)
