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



上下文:我们有一个Blazor应用程序,包含以下3个文件:

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

ChildComponent.rarzor

<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.rarzor

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.rarzor,看起来像这样:

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

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

问题:

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

未处理的异常呈现组件:委派到实例方法不能有null的"this"(参数"this")

可能的解决方案:

ParentComponent.rarzor文件中,我们通过引用传递页脚,并进行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传递给子组件?

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

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

问候,

使用CascadingValue作品:

ParentComponent.rarzor:

<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.rarzor:

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

测试。剃刀:

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

我认为如果你想用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; }
}

如果你不想只为页脚创建另一个组件,你可以通过构建器来完成。OpenElement()。。。并创建所需的元素以及必需的样式和类,所有这些都可以使用属性来完成。布拉佐雷大学是一个网站,有很多很酷的东西。

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

最新更新