如何在 Blazor 中将可选的 RenderFragment 从父组件传递给子组件?

时间:2021-01-28 18:30:07

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

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

  • 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>

我们在这里不使用 <ParentFooter></ParentFooter>,因为页脚是可选的。

问题:

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

<块引用>

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

可能的解决方案:

在文件 ParentComponent.razor 中,我们通过引用传递页脚并进行 null 检查:

<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 传递给子组件?

3 个答案:

答案 0 :(得分:0)

使用 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>

答案 1 :(得分:0)

我认为,如果您想使用 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 :(得分:-1)

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

<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链接

问候,