如何将值从页面传递到 Blazor 中的布局?

How to pass a value from a page to the layout in Blazor?

我有一个布局 (MainLayout.razor),它有一个名为 ShowFooter 的标志。在某些页面上,我希望能够将该标志设置为 true,将其他一些设置为 false

我无法找到关于页面(即具有路由的组件)如何与其布局通信的任何明确说明。 could/should 这在 Blazor 中如何完成?

注意:您可能建议使用 2 种布局,一种有页脚,一种没有页脚,但这并不能真正解决我的问题,我希望能够显示和在同一页的不同时间隐藏页脚。另外,这只是需要在布局和页面之间进行通信的一种情况。还有无数其他的。

您可以使用通知服务并将其注入组件。

public class NotifyService 
{
     public event Func<bool, Task> Notify;

     public async Task Notify(bool value) 
     {
        if (Notify is object)
        {
            await Notify.Invoke(value);
        }
     }
}

然后在 DI 容器中将其注册为单例(如果在服务器端则为范围)并将其注入到您的组件中。

有几种方法可以做到:

  1. 最丑陋的:如果你有两个模板,你可以简单地 select 你想使用的模板,在 page/component 的顶部使用以下内容:

    @layout NoFooterLayoutName

  2. 在模板中使用级联值(我会为您的场景推荐什么):

<CascadingValue Value="Footer">
    <Child />
</CascadingValue>

示例fiddle: https://blazorfiddle.com/s/05spcuyk

和医生:https://docs.microsoft.com/en-us/aspnet/core/blazor/components/cascading-values-and-parameters?view=aspnetcore-5.0

  1. 创建一个 State 服务并将其添加到 startup as scoped。带有 footer bool 变量的状态服务,然后可以注入 pages/components 和使用的变量:

在startup.cs ConfigureService 方法中:

services.AddScoped<AppState>();

在项目的某处创建AppState.cs class(最好是服务文件夹):

public class AppState 
{
   public bool ShowFooter { get; set; }
   public event Action StateChanged;
   private void NotifyStateChanged() => StateChanged?.Invoke();
}

然后将其注入您的 page/components,以便您可以更改 ShowFooter 元素,并在您的模板中为触发 StateHasChanged() 创建事件处理程序(不确定是否需要):

@inject AppState _AppState;
@implements IDisposable
.
.
.
@code{
    protected override void OnInitialized()
    {
        _appState.StateChanged += StateChanged;
    }

    public void StateChanged()
    {
        StateHasChanged();
    }

    public void Dispose()
    {
        _appState.StateChanged -= StateChanged;
    }
}

最简单的方法是在 MainLaout 组件中定义一个名为 ShowFooter 的 public 布尔值 属性,如下所示:

public bool ShowFooter {get; set;}

并通过将标记包装在 Value 属性设置为 thisCascadingValue 组件中,将对 MainLaout 组件的引用级联到给定组件,如下所示:

@inherits LayoutComponentBase


<CascadingValue Value="this">
     <div class="sidebar">
        <NavMenu />
    </div>
    <div class="main">
         <div class="content px-4">
            @Body
        </div>
    </div>
</CascadingValue>
@code
{
    public bool ShowFooter {get; set;}

     protected override void OnInitialized()
    {
      // Put here code that checks the value of ShowFooter and acts in 
      // accordance with your dear wishes

     }
}

在Index.razor

中的用法
@code{
     // Gets a reference to the MainLayout component
    [CascadingParameter]
    public MainLayout Layout { get; set; } 

    protected override void OnInitialized()
    {
        Layout.ShowFooter= true;
    
    }
}