Skip to main content
All docs
V26.1
  • Rows in Blazor Grid

    • 8 minutes to read

    The DevExpress Blazor Grid supports multiple row types:

    DevExpress Blazor Grid — Row Types

    This topic describes row features, customization options, and row operations available in code.

    Row Indexes

    The Grid component assigns indexes to visible data and group rows to indicate row order. Indexes are zero-based and sequential across all Grid pages.

    Row Indexes - All Pages

    DxGrid reassigns row indexes each time users sort, filter, group data, or expand or collapse group rows. Filtered-out rows and rows in collapsed groups do not have indexes. In the following image, the Grid component does not assign indexes to data rows in the collapsed Partly cloudy group.

    Row Indexes - Group Rows

    Get a Row Index

    You can obtain row indexes as follows:

    • Call the GetFocusedRowIndex() method to obtain the focused row’s index.
    • Call the GetStartRowVisibleIndex() method to obtain the index of the first row on the current page.
    • Within a template, use a *VisibleIndex context property to obtain the associated row’s index.
    • In an event handler, use a *VisibleIndex event argument to obtain the processed row’s index.
    • Use values from 0 to Grid.GetVisibleRowCount() - 1 to iterate through all visible rows sequentially.

    Once you obtain a row index, use the following API to obtain information about the row or interact with it.

    Note

    DxGrid bound to an Instant Feedback Data Source or GridDevExtremeDataSource loads data asynchronously in small portions (instead of the entire dataset). Before you call a method that accepts a row index as a parameter, call the WaitForRemoteSourceRowLoadAsync(Int32) method to ensure that the specified data row is loaded.

    Identify Rows

    Pass a row’s index to the following methods to retrieve row data and determine its type and state:

    GetRowLevel
    Gets the nesting level of the processed row.
    GetRowValue
    Gets the value of the data source field in the specified row.
    IsDetailRowExpanded
    Indicates whether the specified detail row is expanded.
    IsEditingRow
    Returns whether the specified Grid row is being edited.
    IsGroupRow
    Specifies whether the specified row is a group row.
    IsGroupRowExpanded
    Specifies whether the specified group row is expanded.
    IsRowFocused
    Identifies whether the row with the specified visible index is focused.
    IsRowSelected
    Returns whether the specified row is selected.

    Interact with Rows

    Call the following methods to change row state in code:

    CollapseDetailRow | ExpandDetailRow
    Collapse/expand the specified detail row.
    CollapseGroupRow | ExpandGroupRow
    Collapse/expand the specified group row.
    DeselectRow | SelectRow
    Select/deselect the specified row.
    DeselectRows | SelectRows
    Select/deselect the specified rows.
    MakeRowVisible | MakeCellVisible
    Navigate to the specified row/cell.
    SetFocusedRowIndex
    Moves focus to the specified row.
    ShowRowDeleteConfirmation
    Displays the delete confirmation dialog for the specified row.
    StartEditRowAsync
    Starts editing the specified row.

    Row Indexes — Code Example

    The following code sample adds a new command to group row context menus: Expand First-Level Groups.

    @using DevExpress.Images.Blazor
    @inject WeatherForecastService ForecastService
    
    <DxGrid Data="@Data"
            ShowGroupPanel="true"
            ContextMenus="@GridContextMenus.GroupRow" 
            CustomizeContextMenu="CustomizeContextMenu">
        <Columns>
            <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
            <DxGridDataColumn FieldName="TemperatureC" Width="150px" />
            <DxGridDataColumn FieldName="Forecast" GroupIndex="1" />
            <DxGridDataColumn FieldName="CloudCover" GroupIndex="0"/>
        </Columns>
    </DxGrid>
    
    @code {
        object Data { get; set; }
    
        protected override void OnInitialized() {
            Data = ForecastService.GetForecast();
        }
        void CustomizeContextMenu(GridCustomizeContextMenuEventArgs args) {
            if (args.Context is GridGroupRowCommandContext) {
                var item = args.Items.AddCustomItem(0, "Expand First-Level Groups", 
                                                       () => ExpandFirstLevelGroups(args.Grid));
                item.IconUrl = @Icon.ArrowMaximizeVerticalDashed;
            }
        }
        static void ExpandFirstLevelGroups(IGrid grid) {
            grid.BeginUpdate();
            for (var i = grid.GetVisibleRowCount() - 1; i >= 0; i--) {
                if (grid.IsGroupRow(i) && grid.GetRowLevel(i) == 0 && !grid.IsGroupRowExpanded(i))
                    grid.ExpandGroupRow(i);
            }
            grid.EndUpdate();
        }
    }
    

    Handle Row Clicks

    The Blazor Grid component raises RowClick and RowDoubleClick events when users click or double-click data and group rows. Handle these events to respond to these actions. The following code example allows users to click group rows to expand/collapse them:

    @inject WeatherForecastService ForecastService
    
    <DxGrid Data="@Data" ShowGroupPanel="true" RowClick="OnRowClick">
        <Columns>
            <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
            <DxGridDataColumn FieldName="TemperatureC" Width="150px" />
            <DxGridDataColumn FieldName="Forecast" GroupIndex="1" />
            <DxGridDataColumn FieldName="CloudCover" GroupIndex="0"/>
        </Columns>
    </DxGrid>
    
    @code {
        object Data { get; set; }
    
        protected override void OnInitialized() {
            Data = ForecastService.GetForecast();
        }
        void OnRowClick(GridRowClickEventArgs e) {
            if (e.Grid.IsGroupRow(e.VisibleIndex)) {
                e.Grid.BeginUpdate();
                if(e.Grid.IsGroupRowExpanded(e.VisibleIndex))
                    e.Grid.CollapseGroupRow(e.VisibleIndex);
                else
                    e.Grid.ExpandGroupRow(e.VisibleIndex);
                e.Grid.EndUpdate();
            }
        }
    }
    

    Row Context Menus

    The DevExpress Blazor Grid allows you to display context menus with predefined and custom commands for the following rows:

    • Data rows
    • Header and footer rows
    • Group and group footer rows

    Use the ContextMenus property to display contextual commands when users right-click Grid elements. Footer, group footer, and data row context menus do not include predefined commands. Handle the CustomizeContextMenu event to add custom commands for these rows.

    The following example enables context menus for Grid rows:

    Read Tutorial: Context Menus Run Demo: Context Menu

    DevExpress Blazor Grid - Row Context Menus

    @inject WeatherForecastService ForecastService
    
    <DxGrid Data="@Data" 
            ShowGroupPanel="true" 
            ContextMenus="AvailableContextMenus"
            CustomizeContextMenu="CustomizeContextMenu">
        <Columns>
            <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
            <DxGridDataColumn FieldName="TemperatureC" Width="150px" />
            <DxGridDataColumn FieldName="Forecast" />
            <DxGridDataColumn FieldName="CloudCover" GroupIndex="0"/>
        </Columns>
        <GroupSummary>
            <DxGridSummaryItem SummaryType="GridSummaryItemType.Max" FieldName="TemperatureC" 
                                                                     FooterColumnName="TemperatureC" />
        </GroupSummary>
        <TotalSummary>
            <DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="Date" />
        </TotalSummary>
    </DxGrid>
    
    @code {
        object Data { get; set; }
        GridContextMenus AvailableContextMenus = GridContextMenus.DataRow 
                                                 | GridContextMenus.Header  | GridContextMenus.Footer 
                                                 | GridContextMenus.GroupRow | GridContextMenus.GroupFooter;
    
        protected override void OnInitialized() {
            Data = ForecastService.GetForecast();
        }
    
        void CustomizeContextMenu(GridCustomizeContextMenuEventArgs args) {
            // Populates empty context menus with predefined commands
            if (args.Context is GridFooterCommandContext) {
                args.Items.Add(GridContextMenuDefaultItemNames.ShowColumnChooser);
                args.Items.Add(GridContextMenuDefaultItemNames.ShowFilterBuilder);
            }
            if (args.Context is GridGroupFooterCommandContext || args.Context is GridDataRowCommandContext) {
                args.Items.Add(GridContextMenuDefaultItemNames.ExpandAll);
                args.Items.Add(GridContextMenuDefaultItemNames.CollapseAll);
            }
        }
    }
    

    Customize Rows

    Highlight Rows on Hover

    Set the HighlightRowOnHover to true to highlight a data row when users hover the mouse pointer over it:

    DevExpress Blazor Grid - Highlight Row on Hover

    @inject WeatherForecastService ForecastService
    
    <DxGrid Data="@Data" HighlightRowOnHover="true">
        <Columns>
            <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
            <DxGridDataColumn FieldName="TemperatureC" Width="150px" />
            <DxGridDataColumn FieldName="Forecast" />
            <DxGridDataColumn FieldName="CloudCover" />
        </Columns>
    </DxGrid>
    
    @code {
        object Data { get; set; }
    
        protected override void OnInitialized() {
            Data = ForecastService.GetForecast();
        }
    }
    

    Conditionally Customize Rows

    Handle the CustomizeElement event to customize row appearance. The following code sample adds tooltips that identify row types:

    @inject WeatherForecastService ForecastService
    
    <DxGrid Data="@Data" 
            ShowGroupPanel="true" 
            ShowFilterRow="true" 
            EditNewRowPosition="GridEditNewRowPosition.FixedOnTop"
            CustomizeElement="Grid_CustomizeElement" >
        <Columns>
            <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
            <DxGridDataColumn FieldName="TemperatureC" Width="150px" />
            <DxGridDataColumn FieldName="Forecast" GroupIndex="1" />
            <DxGridDataColumn FieldName="CloudCover" GroupIndex="0"/>
        </Columns>
        <GroupSummary>
            <DxGridSummaryItem SummaryType="GridSummaryItemType.Max" FieldName="TemperatureC"
                               FooterColumnName="TemperatureC" />
        </GroupSummary>
        <TotalSummary>
            <DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="Date" />
        </TotalSummary>
    </DxGrid>
    
    @code {
        object Data { get; set; }
    
        protected override void OnInitialized() {
            Data = ForecastService.GetForecast();
        }
        void Grid_CustomizeElement(GridCustomizeElementEventArgs e) {
            // Use e.CssClass property to customize an element
            e.Attributes["title"] = e.ElementType switch {
                GridElementType.HeaderRow => "This is a header row",
                GridElementType.DataRow => "This is a data row",
                GridElementType.DetailCell => "This is a detail row",
                GridElementType.GroupRow => "This is a group row",
                GridElementType.FilterRow => "This is a filter row",
                GridElementType.GroupFooterRow => "This is a group footer row",
                GridElementType.FooterRow => "This is a footer row",
                GridElementType.EditNewItemRow => "This is a new item row",
                _ => null
            };
        }
    }
    

    Alternating Row Style

    You can use the CustomizeElement event to highlight alternating (odd) rows with a different style to improve Grid readability:

    Run Demo: Alternating Row Style

    DevExpress Blazor Grid - Alternating Row Style

    @inject NwindDataService NwindDataService
    
    <DxGrid @ref="Grid"
            Data="@Data"
            CustomizeElement="Grid_CustomizeElement"
            VirtualScrollingEnabled="true">
        <Columns>
            <DxGridDataColumn FieldName="CompanyName" MinWidth="100" />
            <DxGridDataColumn FieldName="City" Width="10%" />
            <DxGridDataColumn FieldName="Region" Width="10%" />
            <DxGridDataColumn FieldName="Country" Name="Country" Width="10%" />
            <DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c" Width="10%" />
            <DxGridDataColumn FieldName="Quantity" MinWidth="80" Width="10%" />
            <DxGridDataColumn FieldName="Total"
                              Name="Total"
                              UnboundType="GridUnboundColumnType.Decimal"
                              UnboundExpression="[UnitPrice] * [Quantity]"
                              DisplayFormat="c"
                              MinWidth="100"
                              Width="15%" />
        </Columns>
    </DxGrid>
    
    @code {
        object Data { get; set; }
        IGrid Grid { get; set; }
    
        protected override async Task OnInitializedAsync() {
            var invoices = await NwindDataService.GetInvoicesAsync();
            var customers = await NwindDataService.GetCustomersAsync();
            Data = invoices.OrderBy(i => i.OrderDate).Join(customers, i => i.CustomerId, c => c.CustomerId, (i, c) => {
                return new {
                    CompanyName = c.CompanyName,
                    City = i.City,
                    Region = i.Region,
                    Country = i.Country,
                    UnitPrice = i.UnitPrice,
                    Quantity = i.Quantity
                };
            });
        }
        void Grid_CustomizeElement(GridCustomizeElementEventArgs e) {
            if(e.ElementType == GridElementType.DataRow && e.VisibleIndex % 2 == 1) {
                e.CssClass = "alt-item";
            }
            if(e.ElementType == GridElementType.HeaderCell) {
                e.CssClass = "header-bold";
            }
        }
    }