I have the following files:
BaseComponent.cs:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Test.Pages;
[Route("/basepage")]
public class BasePage :ComponentBase
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
var seq = 0;
builder.OpenElement(seq, "h3");
builder.AddContent(++seq, "BuildRenderTree of BasePage.cs");
builder.CloseElement();
}
}
CustomNonRazorPage.cs:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Xcition.Client.Pages;
[Route("/customnonrazorpage")]
public class CustomNonRazorPage : BasePage
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
var seq = 0;
builder.OpenElement(seq, "h3");
builder.AddContent(++seq, "BuildRenderTree of CustomNonRazorPage.cs");
builder.CloseElement();
}
}
CustomPage.razor:
@inherits BasePage
@page "/custompage"
<h3>CustomPage.razor</h3>
I call the following relative URI in the browser:
/basepage
: returns a page with BuildRenderTree
of BasePage.cs
OK, it calls its own BuildRenderTree
method/customnonrazorpage
: returns a page with BuildRenderTree
of BasePage.cs
and BuildRenderTree
of CustomNonRazorPage.cs
OK, it calls the BuildRenderTree
method of BasePage
/custompage
: returns a page with CustomPage.razor
Unexpected value because it doesn't call the BuildRenderTree
method of BasePage
May be I'm doing something wrong because I'm a beginner in Blazor.
I would like to create my custom base component that surrounds with an another component the body of a child razor component that inherits of my custom base component (something like the Layouts do).
I try to explain it better with an example:
FinalComponent.razor
that inherits from BaseComponent
and with a body like "My final content".
BaseComponent.cs
that implements in BuildRenderTree
the code that surrounds [Parameter] RenderFragment
body with the OtherComponent
OtherComponent.razor
that contains <div>@Body</div>
I would like to get the final result like this:
<div><h3>My final content</h3></div>
The target is to be able to decide by code in the BaseComponent
what is the the class that I would use for the OtherComponent
without need to know it from the FinalComponent
.
Welcome to the world of ComponentBase
.
Unfortunately ComponentBase
wasn't built with "Wrapper" functionality in mind, so making it perform that trick is a little convoluted. The alternative, which I don't recommend when you're new to Blazor, is build your own base component that will support wrapper functionality "out of the box". There are references to articles that explain hoe to do this at the bottom of the article.
The problem with CustomPage
is that:
<h3>CustomPage.razor</h3>
is compiled by the Razor compiler into a protected override void BuildRenderTree(RenderTreeBuilder builder)
method that overrides yours in the parent component.
To make ComponentBase
wrap you need to create and manipulate some RenderFragmnents
.
Here's my demo MyTemplate
. It's in your face red so you can see it's wrapping.
It consists of two readonly RenderFragment
properties. Wrapper
is the actual content you want to wrap around the content provided by the child content in Content
.
@code {
protected RenderFragment Wrapper => __builder =>
{
<div class="bg-danger m-2 p-1">
<h3>MyTemplate</h3>
@this.Content
</div>
};
protected virtual RenderFragment? Content { get; }
}
Now our Child - in this case Index
. The real content goes into the overidden Content
. The content that gets build into BuildRenderTree
is the parent wrapper RenderFragment defined in Wrapper
.
@page "/"
@inherits MyTemplate
@Wrapper
@code {
protected override RenderFragment Content => __builder =>
{
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<span>Welcome to your new app.</span>
<SurveyPrompt Title = "How is Blazor working for you?" />
};
}
The result:
A NONO
Don't do this in a builder.
var seq = 0;
builder.OpenElement(seq, "h3");
builder.AddContent(++seq, "BuildRenderTree of BasePage.cs");
Do this:
builder.OpenElement(1, "h3");
builder.AddContent(2, "BuildRenderTree of BasePage.cs");
See - https://learn.microsoft.com/en-us/aspnet/core/blazor/advanced-scenarios?view=aspnetcore-7.0#sequence-numbers-relate-to-code-line-numbers-and-not-execution-order
For those wishing to build a base component here are links to two [of my] articles on the topic:
It is possible, essentially in the same way as in your CustomNonRazorPage
@inherits BasePage
@page "/custompage"
@{ base.BuildRenderTree(__builder); }
<h3>CustomPage.razor</h3>
but besides being ugly that __builder
is a hack, no warranties.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With