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

Row behaviors

RadGridView manages user mouse and keyboard input over its rows by GridRowBehavior. Depending on the row type, RadGridView introduces different behaviors, listed on the table below:

Row behavior Row type
GridDataRowBehavior GridViewDataRowInfo
GridHierarchyRowBehavior GridViewHierarchyRowInfo
GridNewRowBehavior GridViewNewRowInfo
GridGroupRowBehavior GridViewGroupRowInfo
GridFilterRowBehavior GridViewFilteringRowInfo
GridHeaderRowBehavior GridViewTableHeaderRowInfo
GridDetailViewRowBehavior GridViewDetailsRowInfo

By implementing a specific custom row behavior, developers can change the default row functionality or supplement the existing one.

Let’s start with constructing a hierarchical RadGridView and populate it with data.


public RowBehaviorsForm()
{
    InitializeComponent();

    //Fill data
    DataTable items = new DataTable("Items");
    items.Columns.Add("Id", typeof(int));
    items.Columns.Add("Title", typeof(string));
    items.Columns.Add("IsActive", typeof(bool));

    DataTable subItems = new DataTable("SubItems");
    subItems.Columns.Add("Id", typeof(int));
    subItems.Columns.Add("Name", typeof(string));
    subItems.Columns.Add("ItemId", typeof(int));

    for (int i = 1; i <= 3; i++)
    {
        items.Rows.Add(i, "Item" + i, i % 2 == 0);

        for (int j = 1000; j <= 1005; j++)
        {
            subItems.Rows.Add(j, "SubItem" + j, i);
        }
    }

    //Set up grid hierarchy
    radGridView1.DataSource = items;
    radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

    GridViewTemplate template = new GridViewTemplate();
    template.ReadOnly = true;
    template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

    GridViewRelation relation = new GridViewRelation(radGridView1.MasterTemplate, template);
    relation.ParentColumnNames.Add("Id");
    relation.ChildColumnNames.Add("ItemId");
    radGridView1.MasterTemplate.Templates.Add(template);
    radGridView1.Relations.Add(relation);
    template.ReadOnly = false;
    template.DataSource = subItems;
}

Sub New()
    InitializeComponent()
    'Fill data
    Dim items As New DataTable("Items")
    items.Columns.Add("Id", GetType(Integer))
    items.Columns.Add("Title", GetType(String))
    items.Columns.Add("IsActive", GetType(Boolean))
    Dim subItems As New DataTable("SubItems")
    subItems.Columns.Add("Id", GetType(Integer))
    subItems.Columns.Add("Name", GetType(String))
    subItems.Columns.Add("ItemId", GetType(Integer))
    For i As Integer = 1 To 3
        items.Rows.Add(i, "Item" & i, i Mod 2 = 0)
        For j As Integer = 1000 To 1005
            subItems.Rows.Add(j, "SubItem" & j, i)
        Next
    Next
    'Set up grid hierarchy
    RadGridView1.DataSource = items
    RadGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill
    Dim template As New GridViewTemplate()
    template.[ReadOnly] = True
    template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill
    Dim relation As New GridViewRelation(RadGridView1.MasterTemplate, template)
    relation.ParentColumnNames.Add("Id")
    relation.ChildColumnNames.Add("ItemId")
    RadGridView1.MasterTemplate.Templates.Add(template)
    RadGridView1.Relations.Add(relation)
    template.[ReadOnly] = False
    template.DataSource = subItems
End Sub

By default, when the user hits the Delete key over a certain row, the row is deleted. We will extend this functionality by notifying the user when he tries to delete a parent row, which ChildRows collection is not empty. For this purpose, it is necessary to create a custom grid behavior. To do this, create a new class named CustomGridHierarchyRowBehavior. As we are currently using a hierarchical grid, our class should inherit the GridHierarchyRowBehavior. Override the ProcessDeleteKey method in order to display a MessageBox and proceed with the delete operation after confirmation only:
WinForms RadGridView Using Custom Behavior


public class CustomGridHierarchyRowBehavior : GridHierarchyRowBehavior
{
    protected override bool ProcessDeleteKey(KeyEventArgs keys)
    {
        if (this.GridControl.CurrentRow.ChildRows.Count > 0)
        {
            DialogResult result = MessageBox.Show("The current row has child rows." +
                                                  "Are you sure you want to delete the selected row?", "Confirmation", MessageBoxButtons.YesNo);
            if (result == DialogResult.No)
            {
                return true;
            }
        }

        return base.ProcessDeleteKey(keys);
    }
}

Public Class CustomGridHierarchyRowBehavior
Inherits GridHierarchyRowBehavior
    Protected Overrides Function ProcessDeleteKey(keys As KeyEventArgs) As Boolean
        If Me.GridControl.CurrentRow.ChildRows.Count > 0 Then
            Dim result As DialogResult = MessageBox.Show("The current row has child rows." & "Are you sure you want to delete the selected row?", "Confirmation", MessageBoxButtons.YesNo)
            If result = DialogResult.No Then
                Return True
            End If
        End If
        Return MyBase.ProcessDeleteKey(keys)
    End Function
End Class

Next we will register this behavior in our grid. Add the following code after populating the grid with data:


//register the custom row  behavior
BaseGridBehavior gridBehavior = radGridView1.GridBehavior as BaseGridBehavior;
gridBehavior.UnregisterBehavior(typeof(GridViewHierarchyRowInfo));
gridBehavior.RegisterBehavior(typeof(GridViewHierarchyRowInfo), new CustomGridHierarchyRowBehavior());

'register the custom row  behavior
Dim gridBehavior As BaseGridBehavior = TryCast(RadGridView1.GridBehavior, BaseGridBehavior)
gridBehavior.UnregisterBehavior(GetType(GridViewHierarchyRowInfo))
gridBehavior.RegisterBehavior(GetType(GridViewHierarchyRowInfo), New CustomGridHierarchyRowBehavior())

The next modification we are going to introduce is to override the OnMouseDownLeft method and show the context menu for the GridCheckBoxCellElement, associated with the mouse location. First, it is necessary to use the grid navigator to process selection of the cell element, positioned at the mouse location. Afterwards, show the context menu for the specific cell:


protected override bool OnMouseDownLeft(MouseEventArgs e)
{
    GridCellElement cellElement = this.GetCellAtPoint(e.Location);
    if (cellElement != null && cellElement is GridCheckBoxCellElement)
    {
        GridRowElement rowElement = cellElement.RowElement;
        this.Navigator.BeginSelection(this.GetMouseNavigationContext(e));
        this.Navigator.Select(rowElement.RowInfo, cellElement.ColumnInfo);
        this.Navigator.EndSelection();

        if (!cellElement.IsInValidState(true))
        {
            cellElement = this.GetCellAtPoint(e.Location);
        }
        if (cellElement != null)
        {
            GridViewElement.ContextMenuManager.ShowContextMenu(cellElement);
        }
        return true;
    }

    return base.OnMouseDownLeft(e);
}

Protected Overrides Function OnMouseDownLeft(e As MouseEventArgs) As Boolean
    Dim cellElement As GridCellElement = Me.GetCellAtPoint(e.Location)
    If cellElement IsNot Nothing AndAlso TypeOf cellElement Is GridCheckBoxCellElement Then
        Dim rowElement As GridRowElement = cellElement.RowElement
        Me.Navigator.BeginSelection(Me.GetMouseNavigationContext(e))
        Me.Navigator.[Select](rowElement.RowInfo, cellElement.ColumnInfo)
        Me.Navigator.EndSelection()
        If Not cellElement.IsInValidState(True) Then
            cellElement = Me.GetCellAtPoint(e.Location)
        End If
        If cellElement IsNot Nothing Then
            GridViewElement.ContextMenuManager.ShowContextMenu(cellElement)
        End If
        Return True
    End If
    Return MyBase.OnMouseDownLeft(e)
End Function

WinForms RadGridView Show Context Menu

RadGridView supports rows/cells navigation by default, using the arrow keys. It is possible to customize this behavior as well. In the CustomGridHierarchyRowBehavior class override the ProcessKey method and stop the base grid logic for navigation upwards/downwards if the current row belongs to the MasterTemplate and its “IsActive” cell value is set to false:


public override bool ProcessKey(KeyEventArgs keys)
{
    if (keys.KeyCode == Keys.Up || keys.KeyCode == Keys.Down)
    {
        DataRowView rowView = this.GridControl.CurrentRow.DataBoundItem as DataRowView;
        if (rowView != null && this.GridControl.CurrentRow.ViewTemplate == this.MasterTemplate)
        {
            if ((bool)rowView.Row["IsActive"] == false)
            {
                return true;
            }
        }
    }
    return base.ProcessKey(keys);
}

Public Overrides Function ProcessKey(keys__1 As KeyEventArgs) As Boolean
    If keys__1.KeyCode = Keys.Up OrElse keys__1.KeyCode = Keys.Down Then
        Dim rowView As DataRowView = TryCast(Me.GridControl.CurrentRow.DataBoundItem, DataRowView)
        If rowView IsNot Nothing AndAlso Me.GridControl.CurrentRow.ViewTemplate.Equals(Me.MasterTemplate) Then
            If CBool(rowView.Row("IsActive")) = False Then
                Return True
            End If
        End If
    End If
    Return MyBase.ProcessKey(keys__1)
End Function

Following the demonstrated approach, developers can customize not only the hierarchy rows, but the new row for example, implementing a custom GridNewRowBehavior and registering it for the GridViewNewRowInfo.

See Also

In this article