【问题标题】:How to pass an optional RenderFragment from a parent component to a child component in Blazor?如何将可选的 RenderFragment 从父组件传递到 Blazor 中的子组件?
【发布时间】:2021-05-02 16:56:15
【问题描述】:

背景: 我们有一个 Blazor 应用程序,其中包含以下 3 个文件:

  • ChildComponent.razor
  • ParentComponent.razor
  • Test.razor(这是消费者,它使用父组件)

ChildComponent.razor

<div>
    @if(Body != null)
    {
        @Body
    }

    @if(Footer != null)
    {
        <div class="footer">
            @Footer
        </div>
    }
</div>

@code
{
    [Parameter]
    public RenderFragment Body { get; set; }
    
    [Parameter]
    public RenderFragment Footer { get; set; }
}

ParentComponent.razor

ParentComponent 使用 ChildComponent。我们想将ParentFooter 传递给子组件的Footer:

<ChildComponent Footer="ParentFooter">
    <Body>
        <p>@Text</p>
    </Body>
</ChildComponent>

@code
{
    [Parameter]
    public string Text { get; set; }

    [Parameter]
    public RenderFragment ParentFooter { get; set; }
}

使用文件是 Test.razor,如下所示:

<ParentComponent Text="Hello World"></ParentComponent>

我们在这里不使用&lt;ParentFooter&gt;&lt;/ParentFooter&gt;,因为页脚是可选的。

问题:

我们在浏览器的控制台中得到一个异常:

未处理的异常渲染组件:委托给一个实例 方法不能有 null 'this'(参数 'this')

可能的解决方案:

在文件ParentComponent.razor中,我们通过引用传递Footer并进行null-check:

<ChildComponent Footer="ParentFooter" @ref="m_ChildComponentRef">
    <Body>
        <p>@Text</p>
    </Body>
</ChildComponent>

@code
{
    [Parameter]
    public string Text { get; set; }

    [Parameter]
    public RenderFragment ParentFooter { get; set; }
    
    private ChildComponent m_ChildComponentRef { get; set; }
    
    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        if (ParentFooter != null)
        {
            m_ChildComponentRef.Footer = ParentFooter;
        }
    }   
}

但这是一个不好的方法,因为我们会收到警告:

BL0005:组件参数不应设置在其组件之外。

问题:我们如何将可选的 RenderFragment 传递给子组件?

【问题讨论】:

  • 你解决了这个问题还是你还想知道这个?

标签: c# razor blazor blazor-client-side blazor-webassembly


【解决方案1】:

我想如果你想用RenderFragment 构建你的页脚,它会很容易传递。

父组件

<ChildComponent Footer="@GenerateFooter()" />

@code {
    // Your Method that will generate footer for you
      private RenderFragment GenerateFooter() {
           return builder => {
                   builder.OpenComponent(0, typeof(YourFooterComponent));
                   builder.AddAttribute(1, "YourRandomAttribute", "YourValueForAttribute")
                   builder.CloseComponent();
               }
      }
}

子组件

@*The place where you'd like to show your footer.*@
@Footer


@code{

    [Parameter]
    public RenderFragment Footer { get; set; }

}

如果您不想仅为页脚创建另一个组件,您可以通过 builder.OpenElement()... 来执行此操作,并创建您需要的元素以及必要的样式和类,所有这些都可以使用属性来完成。 BlazoreUniversity 是一个包含很多很酷东西的网站。

如果它对你有帮助,请告诉我,对未来也更好。因为自从问题发布以来已经很晚了。

【讨论】:

    【解决方案2】:

    使用CascadingValue 有效:

    ParentComponent.razor:

    <CascadingValue Value="this">
        <ChildComponent>
            <Body>
                <p>@Text</p>
            </Body>
        </ChildComponent>
    </CascadingValue>
    
    @code
    {
        [Parameter]
        public string Text { get; set; }
    
        [Parameter]
        public RenderFragment ParentFooter { get; set; }
    }
    

    ChildComponent.razor:

    <div>
        @if (Body != null)
        {
            @Body
        }
    
        @if (ParentComponent != null && ParentComponent.ParentFooter != null)
        {
            <div class="footer">
                @ParentComponent.ParentFooter
            </div>
        }
    </div>
    
    @code
    {
        [CascadingParameter]
        public ParentComponent ParentComponent { get; set; }
    
        [Parameter]
        public RenderFragment Body { get; set; }
    }
    

    Test.razor:

    <ParentComponent Text="Hello World">
        @* <ParentFooter>Footer</ParentFooter> // <- Optional *@
    </ParentComponent>
    

    【讨论】:

      【解决方案3】:

      您是否尝试在子组件中将参数设置为默认值 所以它看起来像这样

      <div>
      @if(Body != null)
      {
          @Body
      }
      
      @if(Footer != null)
      {
          @Footer
      }
      
      @code
      {
          [Parameter]
          public RenderFragment Body { get; set; } = null;
          
          [Parameter]
          public RenderFragment Footer { get; set; } = null;
      }
      

      在父组件中你也设置了默认值

       @if(ParentFooter != null)
        {
         <ChildComponent Footer="ParentFooter">
              <Body>
                  <p>@Text</p>
              </Body>
          </ChildComponent>
          }
      else {
      // show something else 
      }
          @code
          {
              [Parameter]
              public string Text { get; set; }
          
              [Parameter]
              public RenderFragment ParentFooter { get; set; } = null;
          }
      

      如果这没有帮助你可以发布 github 链接

      问候,

      【讨论】:

        猜你喜欢
        • 2021-05-22
        • 2022-11-23
        • 2020-06-18
        • 2020-07-30
        • 2021-01-20
        • 1970-01-01
        • 1970-01-01
        • 2020-03-18
        • 2022-08-20
        相关资源
        最近更新 更多