在 Blazor 中,如何将参数从 @Body 级联回布局?

In Blazor, how to cascade a parameter from @Body back to the layout?

我需要更改 header 中微调器的 class - 在获取数据时显示它,完成后将其变为不可见。

使用级联值,我可以在布局中拥有:

<CascadingValue Value="classString">
    @Body
</CascadingValue>

并且在页面中我可以使用 [CascadingParameter] string classStr 访问布局中设置的值。

如果我希望 classString 的布局受到页面中 classStr 更改的影响,我可以级联一个事件,如 here.

所示

但此示例将事件级联到具有 <ChildComponent OnStrChange="@ChangeStr"> 的 child 组件,其中 OnStrChange 是使用 [Parameter] 在 child 组件上定义的。

我试过用 <CascadingValue Value="eventName" Name="event"> 级联事件,但这似乎不起作用。

我可以将事件级联到使用@Body 调用的页面吗?

您可以采取非常迂回的路线,您的布局实现类似 this 的接口并将其自身作为级联参数发送。但是,它还有其他副作用。 另一种选择是为组件之间的无缝通信创建服务。基本上,您可以使用:

public class SpinnerState
{
    public string SpinnerClass {get;set;}
    public Func<Task> OnSpinnerClassChanged {get;set;}
    public async Task SetSpinnerClass(string newClass)
    {
        SpinnerClass = newClass;
        await OnSpinnerClassChanged.Invoke();
    }
}

将此作为会话服务注入:

    services.AddScoped<SpinnerState>();

然后在布局中使用

@inject SpinnerState state
@implements IDisposable
// hook and unhook event listeners in OnInitialized and Dispose methods respectively

    <div class="@state.SpinnerClass"></div>
    
    @Body //etc


@code
{
    protected override void OnInitialized() 
    { 
       state.OnSpinnerClassChanged += ChangeSpinner;
    }
    async Task ChangeSpinner()
    {
       StateHasChanged();
    }
}

子组件更新SpinnerClass时,布局会更新状态。

注意事项:

  1. 最好不要这样做。即不要更新 MainLayout 中的 UIs。问题是每次布局级别刷新都会导致主体刷新。反过来,可能 导致组件丢失它们的状态。相反,(在上面的示例中)让微调器组件监听该事件。这样,对状态的任何更新都仅限于微调器组件。

  2. 更新 UI 以响应一些较长的 运行 请求是您真正感兴趣的 我猜 。因此,不是传递 UI 属性更新,而是引发一些功能事件(如 "UploadingFile" )并让各个组件响应它。

--编辑--

@enet 在这个问题上先发制人,但我会把我的答案作为一个稍微更浓缩的版本。

Layout.razor

<CascadingValue Value = "this">
    @AnythingThatNeedsAccesToTheSpinner
</CascadingValue>

@code {
    bool IsSpinning {get; set;}

    public async Task SetSpinner (bool SpinValue){
        IsSpinning=SpinValue;
    }
}

AnythingThatNeedsAccesToTheSpinner.razor

@code{
    [CascadingParameter]
    Layout Layout {get; set;}

    protected override async Task OnInitializedAsync()
    {
         await Layout.SetSpinner(true);
         await Task.Delay(5000);
         await Layout.SetSpinner(false);
    }
    
}