I have created a simple Blazor application and I need to show a loading screen on the index.razor page. I am not needed to include it on the index.razor page. I am using some indirect way to do it.

First I have created a one class called Appsettings.cs and brought the loading logic inside it

Appsettings.cs

public class AppSettings { public static bool _IsProcessing { get; set; } = false; public static MainLayout _layout { get; set; } = new MainLayout(); public static void Loading(bool isProcessing) { _IsProcessing = isProcessing; if(_layout !=null) _layout .LoadingScreenShowing(_IsProcessing); } } 

Then my index.razor file is like this, when press the below Load button, I need to show the Loading screen.

index.razor

<button onclick="PageLoading">Load</button> @code{ protected override void Oninitialized(){} private void PageLoading(){ AppSettings.Loading(true); this.StateHasChanged(); //do something AppSettings.Loading(false); this.StateHasChanged(); } 

After I have included loading part into the MainLayout.razor not explicitly to the index.razor.

MainLayout.razor

@inherits LayoutComponentBase <PageTitle>BlazorApp1</PageTitle> <div> <div> <NavMenu /> </div> <main> <div> <a href="" target="_blank">About</a> </div> <article> <Loading IsVisible="@IsLoading" @ref="load"/> //loading component @Body </article> </main> </div> 

And I've created a partial class to place the functional part of the main layout.

MainLayout.razor.cs

public partial class MainLayout{ private bool IsLoading; Loading load ; public async void LoadingScreenShowing(bool isLoading) { load = new Loading(); IsLoading = isLoading; this.StateHasChanged();//exception is throwing from this line await Task.CompletedTask; } } 

When execute the this.StateHasChanged() line, I am getting the exception called

System.InvalidOperationException: 'The render handle is not yet assigned.'

Why is this occurring?

4

1 Answer

You can't do it the way your are trying to. Component lifecycles are managed by the Renderer: you can't create a component instance and somehow shoehorn it into a page. That's the reason for the error.

Here's a heavily refactored version of your code that I think does what intend.

The scoped service that maintains the App State (your AppSettings):

public class AppStateService { private bool _isLoaded; public event Action? LoadStateChanged; public bool IsLoaded { get => _isLoaded; set { if (_isLoaded != value) { _isLoaded = value; LoadStateChanged?.Invoke(); } } } } 

registered in program:

builder.Services.AddScoped<AppStateService>(); 

The Loading component - I've used a simple bootstrap alert to display the loading message.

@inject AppStateService appStateService @implements IDisposable @if (!this.appStateService.IsLoaded) { <div> Page Loading... </div> } @code { protected override void OnInitialized() => this.appStateService.LoadStateChanged += this.OnStateChanged; private void OnStateChanged() => this.InvokeAsync(StateHasChanged); public void Dispose() => this.appStateService.LoadStateChanged -= this.OnStateChanged; } 

MainLayout:

@inherits LayoutComponentBase <PageTitle>BlazorApp3</PageTitle> <div> <div> <NavMenu /> </div> <main> <div> <LoginDisplay /> <a href="" target="_blank">About</a> </div> <article> <Loading /> @Body </article> </main> </div> 

And finally the demo page:

@page "/" @inject AppStateService appStateService; <PageTitle>Index</PageTitle> <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> @code{ protected async override Task OnInitializedAsync() { this.appStateService.IsLoaded = false; // emulate an async loading event await Task.Delay(2000); this.appStateService.IsLoaded = true; } } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.