Syncfusion Blazor Data Grid Excel Export - Index was out of range. Must be non-negative and less than the size of the collection.

I'm trying to export this data grid but running into Index was out of range exception.

What's causing this? Please help me fix this.

Minimal Repro (Runnable)

Just click the "Export to Excel" button to see the issue.

https://blazorplayground.syncfusion.com/VtByDvhcFoaoioEF

Error

Unhandled exception rendering component: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at System.Collections.Generic.List`1[[Syncfusion.ExcelExport.Cell, Syncfusion.ExcelExport.Net, Version=30.1.39.0, Culture=neutral, PublicKeyToken=3d67ed1f87d44c89]].get_Item(Int32 index)
   at Syncfusion.ExcelExport.BaseCollection`1[[Syncfusion.ExcelExport.Cell, Syncfusion.ExcelExport.Net, Version=30.1.39.0, Culture=neutral, PublicKeyToken=3d67ed1f87d44c89]].get_Item(Int32 index)
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GenerateStackedRows(GridColumn Col, Int32 RowIndex, Int32 ColDepth, List`1 SpannedCellIndex, Boolean isChildLevelStacked)
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].ProcessStackedHeader(List`1 Cols)
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].IterateElements()
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].ExportHandler()
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1.<ExecuteResult>d__154[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1.<ExportHelper>d__151[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at Syncfusion.Blazor.Grids.Internal.GridExcelExport`1.<ExcelExport>d__152[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at Syncfusion.Blazor.Grids.SfGrid`1.<ExportToExcelAsync>d__64[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at Syncfusion.Blazor.Grids.SfGrid`1.<ExportToExcelAsync>d__63[[Playground.User.DetailGrid.GridRowViewModelV2, Playground.User, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at Playground.User.DetailGrid.ExportAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Syncfusion.Blazor.Internal.SfBaseUtils.<InvokeEvent>d__12`1[[Microsoft.AspNetCore.Components.Web.MouseEventArgs, Microsoft.AspNetCore.Components.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at Syncfusion.Blazor.Buttons.SfButton.OnClickHandler(MouseEventArgs args)
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

4 Replies 1 reply marked as answer

AK Ashish Khanal August 28, 2025 12:04 AM UTC

Minimal Repro code:

@using Syncfusion.Blazor.Grids

<style>
    .detail-grid {
        max-width: 900px;
        margin: 2rem auto;
    }

    .export-bar {
        display: flex;
        justify-content: flex-end;
        margin-bottom: 0.5rem;
    }

    .detail-grid .time-row {
        background-color: #e8e8e8;
    }

    .detail-grid .value-row {
        background-color: #87ceeb;
    }
</style>

<div class="detail-grid">
    <div class="export-bar">
        <SfButton IsPrimary="true" OnClick="ExportAsync">Export to Excel</SfButton>
    </div>
    <SfGrid DataSource="@gridData" @ref="Grid" AllowFiltering="true" EnableHover="false" AllowExcelExport="true">
        <GridEvents RowDataBound="RowDataBoundHandler"
                    QueryCellInfo="QueryCellInfoHandler"
                    ExcelQueryCellInfoEvent="ExcelExportQueryCellInfoHandler"
                    TValue="GridRowViewModelV2"></GridEvents>
        <GridFilterSettings Type="Syncfusion.Blazor.Grids.FilterType.Excel"></GridFilterSettings>
        <GridColumns>
            <GridColumn Field=@nameof(GridRowViewModelV2.Id) IsPrimaryKey="true" Visible="false" />
            <GridColumn HeaderText="My Grid" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center">
                <GridColumns>
                    <GridColumn Field="Model" HeaderText="" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Left" Width="120px" AllowFiltering="true">
                        <Template>
                            @{
                                var row = context as GridRowViewModelV2;
                            }
                            @if (row?.GroupPosition == GroupPosition.First)
                            {
                                <span>@row?.Model</span>
                            }
                            @if (row?.GroupPosition == GroupPosition.Last && row.UpdatedDate is not null)
                            {
                                <span>Updated: @row.UpdatedDate.Value.ToString("G")</span>
                            }
                        </Template>
                    </GridColumn>
                    <GridColumn Field="RowType" HeaderText="" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" Width="80px" AllowFiltering="false"></GridColumn>
                </GridColumns>
            </GridColumn>
            @for (int i = 0; i < dateHeaders.Count; i++)
            {
                var day = dateHeaders[i];
                var amField = $"Day{i}AM";
                var pmField = $"Day{i}PM";
                var dayIndex = i;
                <GridColumn HeaderText="@day.ToString("MM/dd/yyyy")" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center">
                    <GridColumns>
                        <GridColumn Field="@amField" HeaderText="AM" Width="60px" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" AllowFiltering="false">
                            <Template>
                                @{
                                    var row = context as GridRowViewModelV2;
                                    var cellValue = row?.GetCellDisplayValue(dayIndex, "AM") ?? "";
                                }
                                <span>@cellValue</span>
                            </Template>
                        </GridColumn>
                        <GridColumn Field="@pmField" HeaderText="PM" Width="60px" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" AllowFiltering="false">
                            <Template>
                                @{
                                    var row = context as GridRowViewModelV2;
                                    var cellValue = row?.GetCellDisplayValue(dayIndex, "PM") ?? "";
                                }
                                <span>@cellValue</span>
                            </Template>
                        </GridColumn>
                    </GridColumns>
                </GridColumn>
            }
        </GridColumns>
    </SfGrid>
</div>

@code {
    private List<GridRowViewModelV2> gridData = new();
    private List<DateTime> dateHeaders = new();
    SfGrid<GridRowViewModelV2>? Grid;

    private Dictionary<string, (string, string, int)> modelDisplayData = new()
    {
        { "Model1Ord2", ("#FFDDDD", "black", 2) },
        { "Model2Ord1", ("#DDFFDD", "black", 1) },
        { "Model3Ord4", ("#DDFF66", "black", 4) },
        { "Model4Ord3", ("#DDEEFF", "black", 3) }
    };

    protected override Task OnInitializedAsync()
    {
        // Explicitly define the two dates for Day0 and Day1
        dateHeaders = new List<DateTime>
        {
            new DateTime(2025, 7, 10),
            new DateTime(2025, 7, 11)
        };

        // Directly construct the grid data
        gridData = new List<GridRowViewModelV2>
        {
            new()
            {
                Id = 1,
                Model = "Model1Ord2",
                ModelColor = "#FFDDDD",
                ModelTextColor = "black",
                RowType = RowType.Time,
                GroupPosition = GroupPosition.First,
                SortOrder = 2,
                Day0 = dateHeaders[0],
                Day0AM = 8,
                Day0PM = 12,
                Day1 = dateHeaders[1],
                Day1AM = 6,
                Day1PM = 12,
                UpdatedDate = new DateTime(2025, 7, 11, 10, 0, 0)
            },
            new()
            {
                Id = 2,
                Model = "Model1Ord2",
                ModelColor = "#FFDDDD",
                ModelTextColor = "black",
                RowType = RowType.Value,
                GroupPosition = GroupPosition.Last,
                SortOrder = 2,
                Day0 = dateHeaders[0],
                Day0AM = 123,
                Day0PM = 45,
                Day1 = dateHeaders[1],
                Day1AM = 17,
                Day1PM = 87,
                UpdatedDate = new DateTime(2025, 7, 11, 10, 0, 0)
            },
            new()
            {
                Id = 3,
                Model = "Model2Ord1",
                ModelColor = "#DDFFDD",
                ModelTextColor = "black",
                RowType = RowType.Time,
                GroupPosition = GroupPosition.First,
                SortOrder = 1,
                Day0 = dateHeaders[0],
                Day0AM = 9,
                Day0PM = 14,
                Day1 = dateHeaders[1],
                Day1AM = 15,
                Day1PM = 17,
                UpdatedDate = null
            },
            new()
            {
                Id = 4,
                Model = "Model2Ord1",
                ModelColor = "#DDFFDD",
                ModelTextColor = "black",
                RowType = RowType.Value,
                GroupPosition = GroupPosition.Last,
                SortOrder = 1,
                Day0 = dateHeaders[0],
                Day0AM = 45,
                Day0PM = 78,
                Day1 = dateHeaders[1],
                Day1AM = 45,
                Day1PM = 98,
                UpdatedDate = null
            }
        };

        return Task.CompletedTask;
    }

    private async Task ExportAsync()
    {
        try
        {
            if (Grid is null) return;

            await Grid.ShowSpinnerAsync();

            var exportProps = new Syncfusion.Blazor.Grids.ExcelExportProperties
            {
                FileName = "BorderIssueRepro.xlsx",
                Theme = new Syncfusion.Blazor.Grids.ExcelTheme
                {
                    Header = new Syncfusion.Blazor.Grids.ExcelStyle
                    {
                        FontName = "Segoe UI",
                        FontColor = "#333333",
                        FontSize = 12,
                        Bold = true,
                        BackColor = "#e8e8e8"
                    },
                    Record = new Syncfusion.Blazor.Grids.ExcelStyle
                    {
                        FontName = "Segoe UI",
                        FontSize = 11
                    }
                }
            };

            await Grid.ExportToExcelAsync(exportProps);

            await Grid.HideSpinnerAsync();
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    public void RowDataBoundHandler(RowDataBoundEventArgs<GridRowViewModelV2> args)
    {
        var row = args.Data;
        var cssClass = row.GetRowCssClass();
        args.Row.AddClass(new[] { cssClass });
    }

    public void QueryCellInfoHandler(Syncfusion.Blazor.Grids.QueryCellInfoEventArgs<GridRowViewModelV2> args)
    {
        var row = args.Data;
        if (args.Column.Field == nameof(GridRowViewModelV2.Model))
        {
            if (row.GroupPosition == GroupPosition.First)
            {
                args.Cell.AddStyle(new[] { "border-bottom: none", "font-weight: bold" });
            }
            else
            {
                args.Cell.AddStyle(new[] { "border-top: none", "pointer-events: none" });
            }

            args.Cell.AddStyle(new[] { $"background-color: {row.ModelColor}", $"color: {row.ModelTextColor}" });
        }
    }

    public void ExcelExportQueryCellInfoHandler(Syncfusion.Blazor.Grids.ExcelQueryCellInfoEventArgs<GridRowViewModelV2> args)
    {
        var row = args.Data;
        var style = args.Style;

        // Model column: color and bold, try to remove border between time/value rows
        if (args.Column.Field == nameof(GridRowViewModelV2.Model))
        {
            style.BackColor = row.ModelColor;
            style.FontColor = row.ModelTextColor;
            style.Bold = true;
            if (row.GroupPosition == GroupPosition.First)
            {
                style.Borders.Bottom.LineStyle = Syncfusion.ExcelExport.LineStyle.None;
            }
            else if (row.GroupPosition == GroupPosition.Last)
            {
                style.Borders.Top.LineStyle = Syncfusion.ExcelExport.LineStyle.None;
            }
        }
        // RowType column: bold
        if (args.Column.Field == nameof(GridRowViewModelV2.RowType))
        {
            style.Bold = true;
        }
        // Data columns: number format
        if (args.Column.Field.EndsWith("AM") || args.Column.Field.EndsWith("PM"))
        {
            style.NumberFormat = "#,##0";
        }
    }

    public record GridRowViewModelV2
    {
        public int Id { get; init; }
        public string Model { get; init; } = default!;
        public string ModelColor { get; init; } = default!;
        public string ModelTextColor { get; init; } = default!;
        public RowType RowType { get; init; }
        public GroupPosition GroupPosition { get; init; }
        public int SortOrder { get; init; }
        public DateTime Day0 { get; set; }
        public double? Day0AM { get; set; }
        public double? Day0PM { get; set; }
        public DateTime Day1 { get; set; }
        public double? Day1AM { get; set; }
        public double? Day1PM { get; set; }
        public DateTime? UpdatedDate { get; init; }

        public DateTime GetDay(int index) => index switch
        {
            0 => Day0,
            1 => Day1,
            _ => throw new ArgumentOutOfRangeException(nameof(index))
        };

        public void SetDay(int index, DateTime value)
        {
            switch (index)
            {
                case 0: Day0 = value; break;
                case 1: Day1 = value; break;
                default: throw new ArgumentOutOfRangeException(nameof(index));
            }
        }

        public double? GetAM(int index) => index switch
        {
            0 => Day0AM,
            1 => Day1AM,
            _ => throw new ArgumentOutOfRangeException(nameof(index))
        };

        public void SetAM(int index, double? value)
        {
            switch (index)
            {
                case 0: Day0AM = value; break;
                case 1: Day1AM = value; break;
                default: throw new ArgumentOutOfRangeException(nameof(index));
            }
        }

        public double? GetPM(int index) => index switch
        {
            0 => Day0PM,
            1 => Day1PM,
            _ => throw new ArgumentOutOfRangeException(nameof(index))
        };

        public void SetPM(int index, double? value)
        {
            switch (index)
            {
                case 0: Day0PM = value; break;
                case 1: Day1PM = value; break;
                default: throw new ArgumentOutOfRangeException(nameof(index));
            }
        }

        public string GetCellDisplayValue(int dayIndex, string amOrPm)
        {
            if (dayIndex < 0 || dayIndex > 1) return "";
            var value = amOrPm == "AM" ? GetAM(dayIndex) : GetPM(dayIndex);
            return RowType switch
            {
                RowType.Time => value?.ToString() ?? "",
                RowType.Value => value?.ToString("N0") ?? "",
                _ => ""
            };
        }
        public string GetRowCssClass() => RowType switch
        {
            RowType.Time => "time-row",
            RowType.Value => "value-row",
            _ => string.Empty
        };
    }
    public enum GroupPosition { First, Last }
    public enum RowType { Time, Value }
}





SK Sanjay Kumar Suresh Syncfusion Team September 2, 2025 11:53 AM UTC

Hi Ashish Khanal,


Sorry for the delay in getting back to you.


We’d like to inform you that when exporting template columns in the Blazor DataGrid to Excel, the user need to enable the IncludeTemplateColumn property within the ExcelExportProperties. This ensures that the template column is included in the exported Excel file, aligning with your requirement.


To render the exported content in a format similar to the UI, you can customize the output using the ExcelExportQueryCellInfoHandler event as like below.


Code Snippet:

private async Task ExportAsync()

{

     try

     {

         if (Grid is null) return;

 

         await Grid.ShowSpinnerAsync();

 

         var exportProps = new Syncfusion.Blazor.Grids.ExcelExportProperties

         {

             FileName = "BorderIssueRepro.xlsx",

             IncludeTemplateColumn = true,

             ….

         }

….

 

public void ExcelExportQueryCellInfoHandler (Syncfusion.Blazor.Grids.ExcelQueryCellInfoEventArgs<GridRowViewModelV2> args)

{

     var row = args.Data;

     var style = args.Style;

 

     if (args.Column.Field == "Model" && (args.RowIndex % 2 == 0)) // to render excel as like in grid UI.

     {

         args.Cell.Value = string.Empty;

     }


Sample: https://blazorplayground.syncfusion.com/embed/BtLetOXVJWUktgVA?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5


Please check the above sample for more information and get back to us if you have any concerns.


Regards,

Sanjay Kumar Suresh


Marked as answer

AK Ashish Khanal September 2, 2025 02:49 PM UTC

Hi Sanjay,

Thank you for the response.

Turns out, all I needed was this line, and it worked correctly.

IncludeTemplateColumn = true,


Thanks again!



SK Sanjay Kumar Suresh Syncfusion Team September 3, 2025 05:35 AM UTC

Hi Ashish Khanal,


We are happy to hear that the provided solution was helpful. Please get back to us if you need any other assistance.


Regards,

Sanjay Kumar Suresh


Loader.
Up arrow icon