【问题标题】:How to pass a value from a page to the layout in Blazor?如何将值从页面传递到 Blazor 中的布局?
【发布时间】:2021-03-19 18:25:59
【问题描述】:

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

我还没有找到任何关于页面(即带有路由的组件)如何与其布局进行通信的明确说明。如何/应该在 Blazor 中做到这一点?

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

【问题讨论】:

    标签: blazor blazor-server-side blazor-webassembly


    【解决方案1】:

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

    public class NotifyService 
    {
         public event Func<bool, Task> Notify;
    
         public async Task Notify(bool value) 
         {
            if (Notify is object)
            {
                await Notify.Invoke(value);
            }
         }
    }
    

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

    【讨论】:

      【解决方案2】:

      有几种方法可以做到:

      1. 最丑的:如果你有两个模板,你可以简单地在页面/组件的顶部选择你想要使用的模板:

        @layout NoFooterLayoutName

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

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

      小提琴示例: https://blazorfiddle.com/s/05spcuyk

      还有文档:https://docs.microsoft.com/en-us/aspnet/core/blazor/components/cascading-values-and-parameters?view=aspnetcore-5.0

      1. 创建状态服务并将其添加到启动范围内。带有footer bool 变量的状态服务,然后可以注入到使用的页面/组件和变量中:

      在startup.cs的ConfigureService方法中:

      services.AddScoped<AppState>();
      

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

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

      然后将其注入您的页面/组件中,以便您可以更改 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;
          }
      }
      

      【讨论】:

      • 谢谢。我喜欢这个。但是AppState 类可以是静态类,而不是注册为单例服务吗?将其作为单例有什么好处?
      • @Arad AppState 类不应该是静态的,依赖注入将根据用户/请求(范围)实例化该类,状态类应该设计为保存用户状态 - 这可能不是你的想要它做。如果正确理解您的问题,最好的选择可能是让 CascadingValue 在布局组件(MainLayout)上显示/隐藏页脚(bool),以便页面可以将其设置为初始化覆盖方法上可能喜欢的任何内容....
      • @Arad ...但请记住,每个页面都必须设置此项,否则您会遇到某些页面将隐藏页脚的情况,然后在导航到另一个页面时,如果页脚未重置为真,它将保持隐藏状态。
      【解决方案3】:

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

      public bool ShowFooter {get; set;}
      

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

      @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;
          
          }
      }
      

      【讨论】:

      • 谢谢,这很聪明。但是在这与史蒂夫桑德森提到的hereAppState 模式之间,您认为哪种方法更好?你会说这是 hackier 吗?
      • 有几种方法可以做到这一点。在stackoverflow中寻找我的答案,这一切都取决于你想做什么。不,这不是一种更老套的方法。这绝对是做到这一点的方法。史蒂夫桑德森提到 s 的方式是 hacky 方式。它是在 Blazor 开发的早期编写的,当时 Blazor 没有当前的功能和支持的内置组件。这样做。
      • 注意:AppState 模式将组件的状态作为一个整体来处理..
      • 好的。那我就用这个!谢谢。最后一个问题,我会将您的答案标记为已接受:既然我们正在这样做,我们不妨在MainLayout 上拥有公共ElementReference 属性:假设我在MainLayout 中有一个Toast 组件,它公开像Show()Hide()这样的方法,考虑在MainLayout中声明一个ElementReference类型的公共属性引用Toast组件,然后在其他组件中我可以访问该toast组件并执行操作喜欢Layout.Toast.Show()。您认为这是一种合理的方法还是很糟糕?!
      • 显然,即使我调用StateHasChanged() 方法,当我更改组件中的公共属性时,布局也不会重新呈现。这是真的吗?
      猜你喜欢
      • 1970-01-01
      • 2020-10-15
      • 1970-01-01
      • 2021-10-21
      • 1970-01-01
      • 2021-02-04
      • 1970-01-01
      • 2021-05-22
      • 2012-05-20
      相关资源
      最近更新 更多