New to Telerik UI for WinForms? Download free 30-day trial

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 and implement rows reordering.

Figure 1: Rows reordering in self-reference hierarchy

WinForms RadGridView Rows Reordering Self-Reference Hierarchy

1. Populate RadGridView with self-reference hierarchical data:

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;
}

2. Register a custom GridHierarchyRowBehavior which starts the RadGridViewDragDropService when you click with the left mouse button:

Register the custom row behavior

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

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

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(row);
        }
        return base.OnMouseDownLeft(e);
    }
}

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.

private void SubscribeToDragDropEvents()
{
    RadDragDropService svc = this.radGridView1.GridViewElement.GetService<RadDragDropService>();
    svc.PreviewDragStart += svc_PreviewDragStart;
    svc.PreviewDragOver += svc_PreviewDragOver;
    svc.PreviewDragDrop += svc_PreviewDragDrop;
}
private void svc_PreviewDragStart(object sender, PreviewDragStartEventArgs e)
{
    e.CanStart = true;
}
private void svc_PreviewDragOver(object sender, RadDragOverEventArgs e)
{
    GridDataRowElement draggedRowElement = e.DragInstance as GridDataRowElement;
    if (draggedRowElement == null)
    {
        e.CanDrop = false;
        return;
    }
    e.CanDrop = true;
    draggedRowElement.Visibility = ElementVisibility.Hidden;
}
private void svc_PreviewDragDrop(object sender, RadDropEventArgs e)
{
    GridDataRowElement draggedRowElement = e.DragInstance as GridDataRowElement;
    GridDataRowElement targetRowElement = e.HitTarget as GridDataRowElement;
    if (draggedRowElement == null)
    {
        return;
    }
    DataRowView sourceRowView = draggedRowElement.RowInfo.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);
    }
}