问题
I want to have customizable content in my layout page in blazor. I have tried adding a renderfragment parameter to the layout and adding makeup with the same name in my component but it is not rendered in my layout
eg
layout.razor:
<header>
@HeaderContent
</header>
@body
@code
{
[Parameter] public RenderFragment HeaderContent { get; set; }
}
component.razor:
<HeaderContent>
<p>my page specific content</p>
</HeaderContnt>
but the headercontent is rendered in the body. can anybody explain how to do this, or why its not possible in a layout. The only way I have found that works is this but it wont refresh the content if I change a bound parameter inside the render fragment
回答1:
- Flexible Content
- Clears on Navigation
- Updates without any wiring up
MainLayout.razor.cs
@inherits LayoutComponentBase
...
<div class="top-row px-4">
@headerContent
</div>
<div class="content px-4">
<CascadingValue Value="this">
@Body
</CascadingValue>
</div>
...
@code {
RenderFragment headerContent => setHeader?.ChildContent;
SetHeader setHeader;
public void SetHeader(SetHeader setHeader)
{
this.setHeader = setHeader;
Update();
}
public void Update() => StateHasChanged();
}
Setter
public class SetHeader : ComponentBase, IDisposable
{
[CascadingParameter]
public MainLayout MainLayout { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized()
{
MainLayout.SetHeader(this);
base.OnInitialized();
}
protected override bool ShouldRender()
{
var shouldRender = base.ShouldRender();
if (shouldRender)
{
MainLayout.Update();
}
return base.ShouldRender();
}
public void Dispose()
{
MainLayout?.SetHeader(null);
}
}
Usage
<SetHeader>
<p>Current count: @currentCount</p>
</SetHeader>
回答2:
The previous answer was pretty close but it didn't work for me. that's how i do fix it:
MainLayout:
<div class="main">
<div class="top-row px-4">
@headerContent
@*<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>*@
</div>
<div class="content px-4">
<CascadingValue Value="this">
@Body
</CascadingValue>
</div>
</div>
@code {
RenderFragment headerContent => setHeader?.ChildContent;
SetHeader setHeader;
public void SetHeader(SetHeader setHeader)
{
if (setHeader == null) return;
this.setHeader = setHeader;
this.setHeader.OnChange += StateHasChanged;
}
}
SetHeader:
public class SetHeader : ComponentBase, IDisposable
{
[CascadingParameter] public MainLayout MainLayout { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
public event Action OnChange;
protected override void OnInitialized()
{
MainLayout.SetHeader(this);
Update();
base.OnInitialized();
}
public void Update()
{
OnChange?.Invoke();
StateHasChanged();
}
public void Dispose()
{
MainLayout?.SetHeader(null);
}
}
Usage into any razor page:
<SetHeader @ref="@setHeader">
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SetHeader>
Into the code of that page:
SetHeader setHeader;
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
setHeader.Update();
}
Now only one problem remains... when you change page you have to put in that page an empty in order to clear it
来源:https://stackoverflow.com/questions/64369596/template-a-blazor-renderfragment-to-a-layout-from-a-page-or-component