Syncfusion Blazor Chart Legend toggle causes System.InvalidOperationException error

Hi,

My ultimate goal is to get the list of currently visible series/models in a Syncfusion Blazor Chart at any given time, especially after the user toggles series visibility via the legend. This is needed for saving user selections and for other business logic.


What I’ve tried:

- I’m using the `OnLegendClick` event to track my series’ visibility by updating my own model’s `IsVisible` property and setting `args.Cancel = true` to prevent the default behavior.

- This approach seems to work fine in local debug builds.

- However, when the app is published and deployed, I often get the following error when I try to turn on the visibility of a series:


blazor.server.js:1 [2025-12-29T22:45:28.745Z] Error: System.InvalidOperationException: Unable to set property 'Visible' on object of type 'Syncfusion.Blazor.Charts.ChartSeries'. The error was: Object reference not set to an instance of an object.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Syncfusion.Blazor.Charts.Internal.ChartSeriesRendererContainer.FindAxisToSeriesCollection(ChartAxisRenderer x_axisRenderer, ChartAxisRenderer y_axisRenderer)
   at Syncfusion.Blazor.Charts.ChartSeries.FindLayoutChange()
   at Syncfusion.Blazor.Charts.ChartSeries.set_Visible(Boolean value)
   at Microsoft.AspNetCore.Components.Reflection.PropertySetter.CallPropertySetter[TTarget,TValue](Action`2 setter, Object target, Object value)
   at Microsoft.AspNetCore.Components.Reflection.ComponentProperties.<SetProperties>g__SetProperty|3_0(Object target, PropertySetter writer, String parameterName, Object value)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Components.Reflection.ComponentProperties.<SetProperties>g__SetProperty|3_0(Object target, PropertySetter writer, String parameterName, Object value)
   at Microsoft.AspNetCore.Components.Reflection.ComponentProperties.SetProperties(ParameterView& parameters, Object target)
   at Syncfusion.Blazor.SfDataBoundComponent.SetParametersAsync(ParameterView parameters)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.SupplyCombinedParameters(ParameterView directAndCascadingParameters)


Minimal Repro:

https://blazorplayground.syncfusion.com/rXrSMVhuFLbCvrur

- Some series are initially hidden (`Visible=false`).

- I use `OnLegendClick` to toggle my own model’s visibility and set `args.Cancel = true`.

- Open the above link, let the app load and immediately click one of the hidden series. It'll crash. And this happens to me all the time in my Production app. I need a solution to it.

- Also, when the chart is loading and the user tries to toggle a series, it crashes and no matter how many page refreshes you do, it keeps on crashing on toggle.

Image_3286_1767051237394

  - Check out the attached screen recording (chartvisbug3_a54344ce.gif) that shows the issue.

- If you're unable to reproduce it in Syncfusion Blazor Playground, paste the code into a .NET 9 Blazor Server app with Syncfusion.Blazor Version 32.1.19 controls and publish it. And deploy it to IIS. And give it a try.


Questions:

- What's causing this issue and how to fix this?

- How can I robustly and elegantly get the list of currently visible series/models in a Syncfusion Blazor Chart at any given time, reflecting the user’s legend toggles?


What I need:

A reliable, production-safe way to get the currently visible series/models at any time, without running into the `InvalidOperationException` or `NullReferenceException` when toggling legend items.


Thanks for your help!


Attachment: chartvisbug3_a54344ce.gif


3 Replies

DG Durga Gopalakrishnan Syncfusion Team December 30, 2025 01:39 PM UTC

Hi Ashish,


The reported exception occurs because the Chart component begins rendering before the SeriesList is fully populated. This happens due to the asynchronous delay (await Task.Delay) in OnInitializedAsync. During this initial render, the chart is in an empty state, and its internal objects are not properly initialized. If a user interacts with the chart at this point (for example, by clicking a legend item), the application attempts to access these null internal references, resulting in the exception.


To resolve this, we recommend either initializing the data synchronously in OnInitialized() or using a boolean flag in the Razor markup to prevent the chart from rendering until all data is loaded and the component’s internal state is fully built.


For your reference, we have attached a modified sample demonstrating this approach.


@if (isDataLoaded)

{

<SfChart @ref="ChartRef"></SfChart>

}

else

{

    <p>Loading chart data...</p>

}

@code {

private bool isDataLoaded = false; // Add this flag

protected override async Task OnInitializedAsync()

{

    await Task.Delay(500);

 

     SeriesList = AllModelsData

         .Select(m => new SeriesInfo

             {

                 Name = m.Name,

                 Color = m.Color,

                 Data = m.Data,

                 IsVisible = SelectedModels.Contains(m.Name)

             })

         .ToList();

     isDataLoaded = true; // Set flag to true after data is loaded

}

}


Sample : https://blazorplayground.syncfusion.com/BXLyCVgjUdDzBWTr


Please let us know if you have any concerns.


Regards,

Durga Gopalakrishnan.



AK Ashish Khanal December 30, 2025 08:02 PM UTC

Thank you, Durga!


Turns out, this check was all I needed:

@if (SeriesList.Count > 0)
{
<SfChart @ref="ChartRef">
...
</SfChart>
}
else
{
    <p>Chart data not available yet.</p>
}

For async scenarios, which applies to every real-world app, the default list check is always required to avoid weird UI bugs. 

Just this issue wasted so much of my time. 😩 Wish this was posted as an IMPORTANT NOTE in your docs. 😊

Thank you again!

=========================================================================

Full source code for future readers:


@using System.Collections.Generic
@using Syncfusion.Blazor.Charts
@using Syncfusion.Blazor.Buttons

<PageTitle>Syncfusion Series Visibility Bug Repro</PageTitle>

@if (SeriesList.Count > 0)
{
<SfChart @ref="ChartRef">
    <ChartPrimaryXAxis ValueType="Syncfusion.Blazor.Charts.ValueType.Category" />
    <ChartPrimaryYAxis Title="Value" />
    <ChartEvents OnLegendClick="OnChartLegendClick" />
    <ChartSeriesCollection>
        @foreach (var series in SeriesList)
        {
            <ChartSeries DataSource="@series.Data"
                         XName="Category"
                         YName="Value"
                         Name="@series.Name"
                         Fill="@series.Color"
                         Visible="@series.IsVisible"
                         Type="Syncfusion.Blazor.Charts.ChartSeriesType.Line" />
        }
    </ChartSeriesCollection>
    <ChartLegendSettings Visible="true" />
</SfChart>
}
else
{
    <p>Chart data not available yet.</p>
}
<div style="margin-top: 1rem;">
    <SfButton OnClick="SubmitAllSelectedModels">Submit All Selected Models</SfButton>
    <div style="margin-top: 0.5rem;">
        <strong>Currently Visible Series:</strong>
        <ul>
            @foreach (var name in VisibleModelsToShowForTest)
            {
                <li>@name</li>
            }
        </ul>
    </div>
</div>

@code {
    // --- Data Models ---
    public class SeriesInfo
    {
        public string Name { get; set; }
        public string Color { get; set; }
        public bool IsVisible { get; set; }
        public List<DataPoint> Data { get; set; }
    }

    public class DataPoint
    {
        public string Category { get; set; }
        public double Value { get; set; }
    }

    // --- All possible models and their data ---
    private List<(string Name, string Color, List<DataPoint> Data)> AllModelsData = new()
    {
        ("Alpha", "#4472c4", new List<DataPoint> {
            new DataPoint { Category = "08/05-AM", Value = 10 },
            new DataPoint { Category = "08/05-PM", Value = 20 },
            new DataPoint { Category = "08/06-PM", Value = 30 }
        }),
        ("Beta", "#ed7d31", new List<DataPoint> {
            new DataPoint { Category = "08/05-PM", Value = 15 },
            new DataPoint { Category = "08/06-PM", Value = 25 },
            new DataPoint { Category = "08/07-AM", Value = 35 }
        }),
        ("Gamma", "#a5a5a5", new List<DataPoint> {
            new DataPoint { Category = "08/05-PM", Value = 12 },
            new DataPoint { Category = "08/06-PM", Value = 22 },
            new DataPoint { Category = "08/07-AM", Value = 32 }
        })
    };

    // --- Only these models are selected for display ---
    private List<string> SelectedModels = new() { "Alpha" };

    private List<SeriesInfo> SeriesList = new();

    private SfChart ChartRef;
    private List<string> VisibleModelsToShowForTest = new();
    protected override async Task OnInitializedAsync()
    {
       await Task.Delay(500);

        SeriesList = AllModelsData
            .Select(m => new SeriesInfo
                {
                    Name = m.Name,
                    Color = m.Color,
                    Data = m.Data,
                    IsVisible = SelectedModels.Contains(m.Name)
                })
            .ToList();
    }

    // --- This method now correctly reflects legend toggles ---
    private List<string> GetVisibleModels()
    {
        return SeriesList
            .Where(s => s.IsVisible)
            .Select(s => s.Name)
            .ToList();
    }

    private void SubmitAllSelectedModels()
    {
        // Get all currently visible models
        VisibleModelsToShowForTest = GetVisibleModels();

        // You can now save these to DB or use them for other business logic
        // Example: await SaveToDatabase(VisibleModelsToShowForTest);
    }

    void OnChartLegendClick(LegendClickEventArgs args)
    {
        args.Cancel = true;
        // Find the series in our list
        var series = SeriesList.FirstOrDefault(s => s.Name == args.Series.Name);
        if (series != null)
        {
            // Toggle the visibility in our model
            // Note: args.Series.Visible represents the CURRENT state (before toggle)
            // So we want to set IsVisible to the OPPOSITE
            series.IsVisible = !args.Series.Visible;
        }
    }
}




DG Durga Gopalakrishnan Syncfusion Team December 31, 2025 11:25 AM UTC

Ashish,


Thank you for the update. You are absolutely right, using an @if check to handle asynchronous data is a best practice to ensure UI stability in Blazor applications.


We sincerely apologize for the inconvenience and the time you spent on this issue. We will make sure to include this as an important note in our Knowledge Base article so it can help other developers avoid similar challenges. Please feel free to reach out if you have any further suggestions or need assistance.


Loader.
Up arrow icon