Sim*_*mon 9 c# razor blazor blazor-client-side blazor-webassembly
在我们的 Blazor WebAssembly 应用程序中,我们有一个ParentComponent嵌套多个ChildComponents. 有3个文件:
文件:测试.razor
<ParentComponent DataSource="@AccountList">
<ChildComponent TData="Account"><span>@context.FirstName</span></ChildComponent>
<ChildComponent TData="Account"><i>@context.LastName</i></ChildComponent>
<ChildComponent TData="Account"><b>@context.Age</b></ChildComponent>
</ParentComponent>
@code {
// The datasource:
private List<Account> AccountList = new List<Account>() {
new Account() { FirstName = "Sam", LastName = "Soldier", Age = 33},
new Account() { FirstName = "Lisa", LastName = "Johnson", Age = 25},
new Account() { FirstName = "Jonas", LastName = "Peer", Age = 50 }
};
// A Simple Account-Class for the datasource
class Account
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
上面的文件按预期显示了以下数据:
文件:ParentComponent.razor
@typeparam TData
<CascadingValue Value="this" Name="ParentComponent">
@ChildContent
<div class="parent-component">
@foreach (var lData in DataSource)
{
@foreach (var lChild in m_Children)
{
<div class="child-component">
@lChild.ChildContent(lData);
</div>
}
}
</div>
</CascadingValue>
@code {
[Parameter]
public List<TData> DataSource { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
/// Collection of all added child components
private List<ChildComponent<TData>> m_Children = new List<ChildComponent<TData>>();
/// Add a child component (will be done by the child itself)
public void AddChildComponent(ChildComponent<TData> pChildComponent)
{
m_Children.Add(pChildComponent);
StateHasChanged();
}
}
Run Code Online (Sandbox Code Playgroud)
文件:ChildComponent.razor
@typeparam TData
@code {
/// Reference to the parent component
[CascadingParameter(Name = "ParentComponent")]
ParentComponent<TData> ParentComponent { get; set; }
/// Child content of the component.
[Parameter]
public RenderFragment<TData> ChildContent { get; set; }
// add ChildComponent to ParentComponent
protected override void OnInitialized()
{
Console.WriteLine("ChildComponent.OnInitialized");
ParentComponent.AddChildComponent(this);
}
}
Run Code Online (Sandbox Code Playgroud)
问题:文件ParentComponent.razor包含语句 @ChildContent ,这在这里没有意义,因为我们想通过以下方式渲染子项的数据@lChild.ChildContent(lData):
// [...]
<CascadingValue Value="this" Name="ParentComponent">
@ChildContent // <- required, but want to remove, because here is othing to show
<div class="parent-component">
@foreach (var lData in DataSource)
{
@foreach (var lChild in m_Children)
{
<div class="child-component">
@lChild.ChildContent(lData); // We wender the child here
</div>
}
}
// [...]
Run Code Online (Sandbox Code Playgroud)
当我们删除 时@ChildContent,就不会渲染任何内容。因此,@ChildContent似乎需要调用 来渲染子组件,但似乎没有必要,因为我们调用@lChild.ChildContent(lData);. 我们如何在没有语句的情况下呈现数据@ChildContent?
也许 -block 中是否有任何@code可能与 相同的调用@ChildContent?例子:
ParentComponent.razor:
@code {
protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
if (firstRender)
{
ChildContent.Invoke(...); // ???
}
}
}
Run Code Online (Sandbox Code Playgroud)
组件是类,您需要先创建 Component 类的实例,然后才能访问其成员(例如其 ChildContent)。
Component 实例是在首次渲染时由 Blazor 创建的。
为了渲染子组件,它们需要成为 RenderTree 批处理的一部分。
如果“拥有”包含子组件的 RenderFragment (Parent.ChildContent) 的组件(父组件)本身不渲染该 ChildContent,则不会创建子组件实例。
像这样的一行代码正在访问子组件的实例属性,这要求子组件实例在被调用之前存在。
@lChild.ChildContent(lData); // We render the child here
Run Code Online (Sandbox Code Playgroud)
因此,简而言之,您需要在父组件中渲染 ChildContent 以创建子组件的实例并将它们注册到 RenderTree 中。
如果您的子组件确实没有内部逻辑 - 正如您问题中的示例所示 - 那么它根本不需要是一个组件 - 它可以是一个 RenderFragment,这使得您将每个子组件包装在额外标记中的要求变得更加容易,因为 RenderFragment 不会像组件一样被实例化。
如果您编写 Parent 来接受多个子 RenderFragments,如下所示:
@typeparam TData
<div class="parent-component">
@foreach (var lData in DataSource)
{
@foreach (var lChild in m_Children)
{
<div class="child-component">
@lChild(lData);
</div>
}
}
</div>
@code {
[Parameter]
public List<TData> DataSource { get; set; }
[Parameter]
public RenderFragment<TData> ChildFragment { set => m_Children.Add(value); }
/// Collection of all added child fragments
private List<RenderFragment<TData>> m_Children = new List<RenderFragment<TData>>();
}
Run Code Online (Sandbox Code Playgroud)
你可以这样使用它:
<ParentComponent DataSource="@AccountList">
<ChildFragment><span>@context.FirstName</span></ChildFragment>
<ChildFragment><i>@context.LastName</i></ChildFragment>
<ChildFragment><b>@context.Age</b></ChildFragment>
</ParentComponent>
Run Code Online (Sandbox Code Playgroud)
作为额外的好处,您不再需要指定类型,TData因为它可以被推断。
** 注意:此技术仅适用于 RenderFragments,但您当然可以将任何您喜欢的内容放入 ChildFragment 中,包括子组件,并且仍然可以控制输出渲染。
| 归档时间: |
|
| 查看次数: |
7173 次 |
| 最近记录: |