我创建了一个简单的 Blazor 应用程序,我需要在 index.razor 页面上显示加载屏幕。我不需要将其包含在 index.razor 页面上。我正在使用一些间接的方式来做到这一点。
首先,我创建了一个名为 Appsettings.cs 的类,并将加载逻辑带入其中
应用程序设置.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);
}
}
然后我的index.razor文件是这样的,当按下下面的加载按钮时,我需要显示加载屏幕。
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();
}
在我将加载部分包含到 MainLayout.razor 中后,未明确加载到 index.razor 中。
MainLayout.razor
@inherits LayoutComponentBase
<PageTitle>BlazorApp1</PageTitle>
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
<Loading IsVisible="@IsLoading" @ref="load"/> //loading component
@Body
</article>
</main>
</div>
我创建了一个分部类来放置主布局的功能部分。
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;
}
}
当执行 this.StateHasChanged() 行时,我收到称为的异常
System.InvalidOperationException:'渲染句柄尚未 已分配。'
为什么会出现这种情况?
你不能按照你想要的方式去做。 组件生命周期由渲染器管理:您无法创建组件实例并以某种方式将其硬塞到页面中。 这就是错误的原因。
这是您的代码的经过大量重构的版本,我认为它符合您的意图。
维护应用程序状态的范围服务(您的
AppSettings
):
public class AppStateService
{
private bool _isLoaded;
public event Action? LoadStateChanged;
public bool IsLoaded
{
get => _isLoaded;
set
{
if (_isLoaded != value)
{
_isLoaded = value;
LoadStateChanged?.Invoke();
}
}
}
}
在程序中注册:
builder.Services.AddScoped<AppStateService>();
加载组件 - 我使用了一个简单的引导警报来显示加载消息。
@inject AppStateService appStateService
@implements IDisposable
@if (!this.appStateService.IsLoaded)
{
<div class="alert alert-danger">
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;
}
主布局:
@inherits LayoutComponentBase
<PageTitle>BlazorApp3</PageTitle>
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4 auth">
<LoginDisplay />
<a href="https://learn.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
<Loading />
@Body
</article>
</main>
</div>
最后是演示页面:
@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;
}
}