如何用rendertreebuilder动态构建父子组件?
How to dynamically build parent and child components with rendertreebuilder?
我需要有关使用 rendertreebuilder 动态 building/generating 多步组件的帮助。
我有两个组件:MultistepComponent(父级)和 MultiStepNavigation(子级)。我还有一个组件构建器 class 来构建这些组件。
渲染组件不工作,我得到一个错误:
Object reference not set to an instance of an object.
那是因为MultiStepNavigation中的MultiStepComponent属性是空的。在 razor 页面中使用组件不会出现此错误。
我将发布大量代码,但您不必阅读每个细节。我只想提供所有信息。
MultiStepComponent.razor
<CascadingValue Value="this">
<div id="@Id">
<ul class="nav nav-pills nav-justified">
@foreach (var step in Steps)
{
<li id="step-@(StepsIndex(step) + 1)" class="nav-item">
<a class="nav-link @((ActiveStep == step) ? "active" : "")" href="javascript: void(0)"
@onclick="@(e=> SetActive(step))">@step.Name</a>
</li>
}
</ul>
<div id="container-fluid">
<div class="navigatingBtns">
<button class="btn btn-primary btn-lg" type="button"
disabled="@(ActiveStepIndex == 0)" @onclick="GoBack">
Previous
</button>
<button class="btn btn-primary btn-lg"
type="@(IsLastStep ? "submit" : "button")" @onclick="GoNext">
@(IsLastStep ? "Submit" : "Next")
</button>
</div>
@ChildContent
</div>
</div>
</CascadingValue>
MultiStepComponent.razor.cs
public partial class MultiStepComponent {
protected internal List<MultiStepNavigation> Steps = new List<MultiStepNavigation>();
[Parameter]
public string Id { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public MultiStepNavigation? ActiveStep { get; set; }
[Parameter]
public int ActiveStepIndex { get; set; }
public bool IsLastStep { get; set; }
protected internal void GoBack()
{
if (ActiveStepIndex > 0)
{
SetActive(Steps[ActiveStepIndex - 1]);
}
}
protected internal void GoNext()
{
if (ActiveStepIndex < Steps.Count - 1)
{
SetActive(Steps[(Steps.IndexOf(ActiveStep) + 1)]);
}
}
protected internal void SetActive(MultiStepNavigation step)
{
ActiveStepIndex = StepsIndex(step);
if (ActiveStepIndex == Steps.Count - 1)
{
IsLastStep = true;
}
else
{
IsLastStep = false;
}
}
public int StepsIndex(MultiStepNavigation step) => StepsIndexInternal(step);
protected int StepsIndexInternal(MultiStepNavigation step)
{
return Steps.IndexOf(step);
}
protected internal void AddStep(MultiStepNavigation step)
{
Steps.Add(step);
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
SetActive(Steps[0]);
StateHasChanged();
}
}
}
MultiStepNavigation.razor
@if (MultiStepComponent.ActiveStep == this) {
<div id="step-@(MultiStepComponent.StepsIndex(this) + 1)">
@ChildContent
</div>
}
MultiStepNavigation.razor.cs
public partial class MultiStepNavigation
{
[CascadingParameter]
protected internal MultiStepComponent MultiStepComponent { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public string Name { get; set; } = "";
protected override void OnInitialized()
{
if(MultiStepComponent != null)
{
MultiStepComponent.AddStep(this);
}
}
}
构建组件的代码:
renderFragment = b =>
{
b.OpenComponent<MultiStepComponent>(0);
b.AddAttribute(1, "id", "MultiStepContainer");
b.OpenComponent<MultiStepNavigation>(2);
b.AddAttribute(3, "Name", "First Step");
b.CloseComponent();
b.CloseComponent();
};
自己在razor page上做组件不报错。它看起来像这样:
<MultiStepComponent Id="MultiStepContainer">
<MultiStepNavigation Name="First Step"></MultiStepNavigation>
</MultiStepComponent>
我做错了什么??
您的代码没有考虑到 MultiStepNavigation
是 MultiStepComponent
的子内容这一事实。
查看 /obj/debug/net5.0/razor/...,找到您的组件的 razor 版本并查看代码。
您可能需要这样做:
private RenderFragment _MultiStepNavigationFragment => b =>
{
b.OpenComponent<MultiStepNavigation>(0);
b.AddAttribute(1, "Name", "First Step");
b.AddAttribute(2, "ChildContent", this.ChildContent);
b.CloseComponent();
};
private RenderFragment _MultiStepComponentFragment => b =>
{
b.OpenComponent<MultiStepComponent>(0);
b.AddAttribute(1, "id", "MultiStepContainer");
b.AddAttribute(2, "ChildContent", this._MultiStepNavigationFragment);
b.CloseComponent();
};
我需要有关使用 rendertreebuilder 动态 building/generating 多步组件的帮助。
我有两个组件:MultistepComponent(父级)和 MultiStepNavigation(子级)。我还有一个组件构建器 class 来构建这些组件。
渲染组件不工作,我得到一个错误:
Object reference not set to an instance of an object.
那是因为MultiStepNavigation中的MultiStepComponent属性是空的。在 razor 页面中使用组件不会出现此错误。
我将发布大量代码,但您不必阅读每个细节。我只想提供所有信息。
MultiStepComponent.razor
<CascadingValue Value="this">
<div id="@Id">
<ul class="nav nav-pills nav-justified">
@foreach (var step in Steps)
{
<li id="step-@(StepsIndex(step) + 1)" class="nav-item">
<a class="nav-link @((ActiveStep == step) ? "active" : "")" href="javascript: void(0)"
@onclick="@(e=> SetActive(step))">@step.Name</a>
</li>
}
</ul>
<div id="container-fluid">
<div class="navigatingBtns">
<button class="btn btn-primary btn-lg" type="button"
disabled="@(ActiveStepIndex == 0)" @onclick="GoBack">
Previous
</button>
<button class="btn btn-primary btn-lg"
type="@(IsLastStep ? "submit" : "button")" @onclick="GoNext">
@(IsLastStep ? "Submit" : "Next")
</button>
</div>
@ChildContent
</div>
</div>
</CascadingValue>
MultiStepComponent.razor.cs
public partial class MultiStepComponent {
protected internal List<MultiStepNavigation> Steps = new List<MultiStepNavigation>();
[Parameter]
public string Id { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public MultiStepNavigation? ActiveStep { get; set; }
[Parameter]
public int ActiveStepIndex { get; set; }
public bool IsLastStep { get; set; }
protected internal void GoBack()
{
if (ActiveStepIndex > 0)
{
SetActive(Steps[ActiveStepIndex - 1]);
}
}
protected internal void GoNext()
{
if (ActiveStepIndex < Steps.Count - 1)
{
SetActive(Steps[(Steps.IndexOf(ActiveStep) + 1)]);
}
}
protected internal void SetActive(MultiStepNavigation step)
{
ActiveStepIndex = StepsIndex(step);
if (ActiveStepIndex == Steps.Count - 1)
{
IsLastStep = true;
}
else
{
IsLastStep = false;
}
}
public int StepsIndex(MultiStepNavigation step) => StepsIndexInternal(step);
protected int StepsIndexInternal(MultiStepNavigation step)
{
return Steps.IndexOf(step);
}
protected internal void AddStep(MultiStepNavigation step)
{
Steps.Add(step);
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
SetActive(Steps[0]);
StateHasChanged();
}
}
}
MultiStepNavigation.razor
@if (MultiStepComponent.ActiveStep == this) {
<div id="step-@(MultiStepComponent.StepsIndex(this) + 1)">
@ChildContent
</div>
}
MultiStepNavigation.razor.cs
public partial class MultiStepNavigation
{
[CascadingParameter]
protected internal MultiStepComponent MultiStepComponent { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public string Name { get; set; } = "";
protected override void OnInitialized()
{
if(MultiStepComponent != null)
{
MultiStepComponent.AddStep(this);
}
}
}
构建组件的代码:
renderFragment = b =>
{
b.OpenComponent<MultiStepComponent>(0);
b.AddAttribute(1, "id", "MultiStepContainer");
b.OpenComponent<MultiStepNavigation>(2);
b.AddAttribute(3, "Name", "First Step");
b.CloseComponent();
b.CloseComponent();
};
自己在razor page上做组件不报错。它看起来像这样:
<MultiStepComponent Id="MultiStepContainer">
<MultiStepNavigation Name="First Step"></MultiStepNavigation>
</MultiStepComponent>
我做错了什么??
您的代码没有考虑到 MultiStepNavigation
是 MultiStepComponent
的子内容这一事实。
查看 /obj/debug/net5.0/razor/...,找到您的组件的 razor 版本并查看代码。
您可能需要这样做:
private RenderFragment _MultiStepNavigationFragment => b =>
{
b.OpenComponent<MultiStepNavigation>(0);
b.AddAttribute(1, "Name", "First Step");
b.AddAttribute(2, "ChildContent", this.ChildContent);
b.CloseComponent();
};
private RenderFragment _MultiStepComponentFragment => b =>
{
b.OpenComponent<MultiStepComponent>(0);
b.AddAttribute(1, "id", "MultiStepContainer");
b.AddAttribute(2, "ChildContent", this._MultiStepNavigationFragment);
b.CloseComponent();
};