Object reference not set to an instance of an object

I'm attempting to utilise a generic Grid component, like this:

@typeparam T
 
<div class="gridWrapper">
    @if (loaded)
    {
        <SfGrid DataSource="@(DataSource)" Toolbar="@(ToolBar)" AllowFiltering="true" AllowPaging="true" AllowSelection="true" AllowSorting="true" Width="100%" AllowPdfExport="true" AllowExcelExport="true" AllowTextWrap="true" AllowGrouping="true">
            @if (GridCommandModel.GetIcons().Any())
        {
            <GridEvents TValue="T" CommandClicked="@(OnCommandClicked)"></GridEvents>
        }
        <GridEvents OnToolbarClick="@(OnToolbarClicked)" TValue="T"></GridEvents>
        @if (GridSortColumns.Any())
        {
            <GridSortSettings>
                <GridSortColumns>
                    @foreach (var column in GridSortColumns)
                    {
                        <GridSortColumn Field="@(column.GetField())" Direction="@(column.GetDirection())"></GridSortColumn>
                    }
                </GridSortColumns>
            </GridSortSettings>
        }
        <GridColumns>
            @foreach (var column in GridColumns)
            {
                @if (column.GetWidth() > 0)
                {
                    <GridColumn Field="@(column.GetField())" HeaderText="@(column.GetHeaderText())" Width="@($"{column.GetWidth().ToString()}px")"></GridColumn>
                }
                else
                {
                    <GridColumn Field="@(column.GetField())" HeaderText="@(column.GetHeaderText())"></GridColumn>
                }
            }
            @if (GridCommandModel.GetIcons().Any())
            {
                @if (GridCommandModel.GetWidth() > 0)
                {
                    <GridColumn TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" Field="@(GridCommandModel.GetHeaderText())" Width="@($"{GridCommandModel.GetWidth()}px")">
                        <GridCommandColumns>
                            @foreach (var icon in GridCommandModel.GetIcons())
                            {
                                <GridCommandColumn ButtonOption="@(new CommandButtonOptions() {IconCss = icon})"></GridCommandColumn>
                            }
                        </GridCommandColumns>
                    </GridColumn>
                }
                else
                {
                    <GridColumn TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" Field="@(GridCommandModel.GetHeaderText())">
                        <GridCommandColumns>
                            @foreach (var icon in GridCommandModel.GetIcons())
                            {
                                <GridCommandColumn ButtonOption="@(new CommandButtonOptions() {IconCss = icon})"></GridCommandColumn>
                            }
                        </GridCommandColumns>
                    </GridColumn>
                }
            }
        </GridColumns>
    </SfGrid>
    }
</div>
 
@code {
    [Parameter]
    public IEnumerable<T> DataSource { get; set; }
    [Parameter]
    public List<GridColumnModel> GridColumns { get; set; }
    [Parameter]
    public List<GridSortColumnModel> GridSortColumns { get; set; }
    [Parameter]
    public List<string> ToolBar { get; set; }
    [Parameter]
    public GridCommandModel GridCommandModel { get; set; }
    [Parameter]
    public EventCallback<ClickEventArgs> OnToolbarClicked { get; set; }
    [Parameter]
    public EventCallback<CommandClickEventArgs<T>> OnCommandClicked { get; set; }
    private bool loaded = false;
    protected override async Task OnParametersSetAsync()
    {
        loaded = true;
        StateHasChanged();
    }
}

Where the column model is like so: 

using TextAlign = Syncfusion.Blazor.Grids.TextAlign;
 
namespace FIS2withSyncfusion.Models
{
    public class GridColumnModel
    {
        private string Field;
        private string HeaderText;
        private TextAlign TextAlign = TextAlign.Center;
        private int? Width;
        private bool WidthSet = false;
        public GridColumnModel(string field, string headerText)
        {
            Field = field;
            HeaderText = headerText;
        }
        public GridColumnModel(string field, string headerText, int width)
        {
            Field = field;
            HeaderText = headerText;
            Width = width;
            WidthSet = true;
        }
        public string GetField()
        {
            return Field;
        }
        public string GetHeaderText()
        {
            return HeaderText;
        }
        public TextAlign GetTextAlign()
        {
            return TextAlign;
        }
        public int GetWidth()
        {
            return WidthSet ? Width.Value : 0;
        }
        public void SetTextAlign(TextAlign textAlign)
        {
            TextAlign = textAlign;
        }
    }
}

The Sort Column model is as follows:

using SortDirection = Syncfusion.Blazor.Grids.SortDirection;
 
namespace FIS2withSyncfusion.Models
{
    public class GridSortColumnModel
    {
        private bool Ascending;
        private string Field;
        public GridSortColumnModel(string field, bool ascending = true)
        {
            Field = field;
            Ascending = ascending;
        }
        public SortDirection GetDirection()
        {
            return Ascending ? SortDirection.Ascending : SortDirection.Descending;
        }
        public string GetField()
        {
            return Field;
        }
    }
}

And the command model is: 

using System.Collections.Generic;
 
namespace FIS2withSyncfusion.Models
{
    public class GridCommandModel
    {
        private string HeaderText;
        private List<string> Icons;
        private int? Width;
        public GridCommandModel(string headerText)
        {
            HeaderText = headerText;
            Icons = new List<string>();
        }
        public GridCommandModel(string headerText, int width)
        {
            HeaderText = headerText;
            Width = width;
            Icons = new List<string>();
        }
        public void AddIcon(string icon)
        {
            Icons.Add(icon);
        }
        public string GetHeaderText()
        {
            return HeaderText;
        }
        public List<string> GetIcons()
        {
            return Icons;
        }
        public int GetWidth()
        {
            return Width ?? 0;
        }
    }
}

A limited example of a use case for it would be:

@using FIS2withSyncfusion.Shared.Email
@using System.Diagnostics.Eventing.Reader
@using Microsoft.EntityFrameworkCore
@using TextAlign = Syncfusion.Blazor.Grids.TextAlign
@inject IDbContextFactory<FIS2_DbContext> _contextFactory;
@inject SessionState _state;
@inject IEmailService _emailService;
 
@if (loaded)
{
    <div class="dashWrapper">
        <SfDashboardLayout AllowDragging="false" AllowFloating="false" AllowResizing="false" CellAspectRatio="2.5" CellSpacing="@(new double[]{20,20})" Columns="3">
            <DashboardLayoutPanels>
                <DashboardLayoutPanel Column="0" Row="0" SizeX="2" SizeY="2" Id="notesGrid">
                    <HeaderTemplate>
                        <h3>Notes</h3>
                    </HeaderTemplate>
                    <ContentTemplate>
                        <FIS2withSyncfusion.Controls.Grid T="@(GetAllStudentNotesResult)" DataSource="@(notes)" ToolBar="@(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel", "PdfExport", "ExcelExport" })" GridColumns="@(GridColumns)" GridCommandModel="@(CommandModel)" GridSortColumns="@(GridSortColumns)" OnToolbarClicked="@(OnGridToolbarClicked)" OnCommandClicked="@(OnGridCommandClicked)"></FIS2withSyncfusion.Controls.Grid>
                    </ContentTemplate>
                </DashboardLayoutPanel>
            </DashboardLayoutPanels>
        </SfDashboardLayout>
    </div>
}
 
@code {
    [Parameter]
    public string StudentId { get; set; }
    private bool loaded = false;
    private List<GridColumnModel> GridColumns = new();
    private List<GridSortColumnModel> GridSortColumns = new();
    private GridCommandModel CommandModel;
    private List<GetAllStudentNotesResult> notes;
    private List<string> GridToolbar = new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel", "PdfExport", "ExcelExport" };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            GetGridColumns();
            GetGridSortColumns();
            GetGridCommandModel();
            await GetAllStudentNotes();
            loaded = true;
            StateHasChanged();
        }
    }
    private void GetGridColumns()
    {
        GridColumns = new List<GridColumnModel>();
        GridColumns.Add(new GridColumnModel(nameof(GetAllStudentNotesResult.CreatedDate), "Created"));
        GridColumns.Add(new GridColumnModel(nameof(GetAllStudentNotesResult.CreatedBy), "Created By"));
        GridColumns.Add(new GridColumnModel(nameof(GetAllStudentNotesResult.NoteType_Desc), "Note Type"));
        GridColumns.Add(new GridColumnModel(nameof(GetAllStudentNotesResult.NoteSubType_Desc), "Note Sub Type"));
        GridColumns.Add(new GridColumnModel(nameof(GetAllStudentNotesResult.NoteDetails), "Note"));
    }
    private void GetGridSortColumns()
    {
        GridSortColumns = new List<GridSortColumnModel>();
        GridSortColumns.Add(new GridSortColumnModel(nameof(GetAllStudentNotesResult.CreatedDate), false));
    }
    private void GetGridCommandModel()
    {
        CommandModel = new GridCommandModel("Commands", 150);
        CommandModel.AddIcon("fa fa-trash-can");
    }
    private async Task GetAllStudentNotes()
    {
        var context = _contextFactory.CreateDbContext();
        var procedures = context.Procedures;
        notes = await procedures.GetAllStudentNotesAsync(StudentId);
    }
    private async Task OnGridToolbarClicked(ClickEventArgs args)
    {
    }
    private async Task OnGridCommandClicked(CommandClickEventArgs<GetAllStudentNotesResult> args)
    {
    }
}

Unfortunately, at some point while rendering the component, it receives a NullReferenceException. I've stepped through the code several times and can't find where the exception is coming from. Is there any kind of pointer you can give me?


1 Reply

VN Vignesh Natarajan Syncfusion Team December 10, 2021 06:33 AM UTC

Hi Andy,  
 
Greetings from Syncfusion support.  
 
Query: “Object reference not set to an instance of an object” 
 
We are able to reproduce the reported issue at our end also when preparing a sample using your code example. Primary cause of the issue is due to GridCommandColumns definition in Grid component. You have defined the Field property to GridCommandColumns. When Field property is defined, Grid will try to fetch its details from the Grid datasource to display in the column. You have defined the headertext value of GridCommandModel to Field property where notes property will not have definition for commands column. Hence the reported issue has occurred.  
 
Kindly replace the Field property in GridColumn defintion of Command column with HeaderText property to resolve the primary issue. Refer the below code example for your reference   
 
@if (GridCommandModel.GetIcons().Any()) 
{ 
    @if (GridCommandModel.GetWidth() > 0) 
    { 
        <GridColumn TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" HeaderText="@(GridCommandModel.GetHeaderText())" Width="@($"{GridCommandModel.GetWidth()}px")"> 
            <GridCommandColumns> 
                @foreach (var icon in GridCommandModel.GetIcons()) 
                { 
                    <GridCommandColumn ButtonOption="@(new CommandButtonOptions() {IconCss = icon})"></GridCommandColumn> 
                } 
            </GridCommandColumns> 
        </GridColumn> 
    } 
    else 
    { 
        <GridColumn TextAlign="Syncfusion.Blazor.Grids.TextAlign.Center" HeaderText="@(GridCommandModel.GetHeaderText())"> 
            <GridCommandColumns> 
                @foreach (var icon in GridCommandModel.GetIcons()) 
                { 
                    <GridCommandColumn ButtonOption="@(new CommandButtonOptions() {IconCss = icon})"></GridCommandColumn> 
                } 
            </GridCommandColumns> 
        </GridColumn> 
    } 
} 
 
 
Another issue we faced is Grid component is being rendered before its value being initiated. You have used loaded property render the Grid which is initiated in the same razor. Instead we request you to pass loaded value as parameter to Grid component. So that Grid will rendered after all the instances get updated.  
 
Refer the below code example  
 
[Grid.Razor] 
 
[Parameter]   public bool Loaded { getset; }
 
[Index.razor] 
 
<Grid T="@(GetAllStudentNotesResult)" Loaded="@loaded" DataSource="@(notes)" ToolBar="@(new List<string>() { "Add""Edit""Delete""Update""Cancel""PdfExport""ExcelExport" })" GridColumns="@(GridColumns)" GridCommandModel="@(CommandModel)" GridSortColumns="@(GridSortColumns)" OnToolbarClicked="@(OnGridToolbarClicked)" OnCommandClicked="@(OnGridCommandClicked)"> </Grid>@code{        private bool loaded = false;    protected override async Task OnAfterRenderAsync(bool firstRender)    {        if (firstRender)        {            GetGridColumns();            GetGridSortColumns();            GetGridCommandModel();            await GetAllStudentNotes();            loaded = true;            StateHasChanged();        }    }
 
 
Please find the modified sample from the below. 
 
 
Please get back to us if you have further queries.  
 
Regards, 
Vignesh Natarajan  
 


Loader.
Up arrow icon