【发布时间】:2021-01-29 17:50:46
【问题描述】:
假设我们有一个基本组件ParentComponent.razor:
<div id="ParentComponent">@ChildContent</div>
@code {
[Parameter] public RenderFragment ChildContent {get;set;}
}
可以这样使用:
<ParentComponent>
<div>content</div>
</ParentComponent>
会渲染:
<div id="ParentComponent"><div>content</div></div>
但是假设我们希望 ChildComponent.razor 继承自 ParentComponent.razor:
@inherits ParentComponent
<div id="ChildComponent">@ChildContent</div>
@code {
[Parameter] public RenderFragment ChildContent {get;set;}
}
有没有办法从 ChildComponent 填充 ParentComponent 的 @ChildContentRenderFragment?
<ChildComponent>
child content
</ChildComponent>
制作这个:
<div id="ParentComponent">
<div id="ChildComponent">child content</div>
</div>
不知道我是否遗漏了一些明显的东西,但一直在弄乱它并且无法在互联网上找到任何答案。
编辑 - 替代解决方案
我发现了另一种方法,它不依赖于直接覆盖 BuildRenderTree 方法,并且允许您使用 html/razor 标记,尽管这确实意味着在房屋周围走动。也不确定这是否安全或高效,但为了完整起见将其放在这里。
ParentElement.razor
@using Microsoft.AspNetCore.Components.Rendering;
@if (!HasRendered()) {
SetRenderedStatus();
<div id="ParentComponent">
RenderChild(__builder);
</div>
}
@code {
protected bool _hasBaseRendered = false;
protected bool HasRendered() {
return _hasBaseRendered;
}
protected void SetRenderedStatus() {
_hasBaseRendered = true;
}
protected virtual void RenderChild(RenderTreeBuilder __builder) { }
}
ChildElement.razor
@using Microsoft.AspNetCore.Components.Rendering
@inherits ParentElement
@if (HasRendered()) {
<div id="ChildComponent">
@ChildContent
</div>
}
@{
base.BuildRenderTree(__builder);
}
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
protected override void RenderChild(RenderTreeBuilder __builder) {
this.BuildRenderTree(__builder);
}
}
如此快速的解释,IDE/Compiler 中的功能清楚地将代码的 razor/html 标记部分编译为幕后的 BuildRenderTree 方法,这就是为什么您不能在 .razor 中覆盖这些方法的原因组件。
上面的代码编译成:
ChildElement.razor
protected override void BuildRenderTree(RenderTreeBuilder __builder)
{
if (HasRendered())
{
__builder.AddContent(0, " ");
__builder.OpenElement(1, "div");
__builder.AddAttribute(2, "id", "ChildComponent");
__builder.AddMarkupContent(3, "\r\n ");
__builder.AddContent(4, ChildContent);
__builder.AddMarkupContent(5, "\r\n ");
__builder.CloseElement();
__builder.AddMarkupContent(6, "\r\n");
}
base.BuildRenderTree(__builder);
}
所以当 HasRendered 为 false 时 ChildContent 被忽略,它被定向调用父类上的 base.BuildRenderTree。
ParentElement.razor
protected override void BuildRenderTree(RenderTreeBuilder __builder)
{
if (!HasRendered())
{
SetRenderedStatus();
__builder.AddContent(0, " ");
__builder.OpenElement(1, "div");
__builder.AddAttribute(2, "id", "ParentComponent");
__builder.AddMarkupContent(3, "\r\n");
RenderChild(__builder);
__builder.AddContent(4, " ");
__builder.CloseElement();
__builder.AddMarkupContent(5, "\r\n");
}
}
它呈现父母标记,中途被定向到RenderChild,它被孩子覆盖,这将流回到孩子的一个级别,然后调用它的BuildRenderTree,HasRendered检查将确保避免无限循环,然后呈现标记的子部分,然后返回到父级以完成。
这可能会被重构,只是我当前的工作副本实验。
【问题讨论】: