我有一个自定义组件,带有一个名为TabChanged的事件action。在我的Razor页面中,我将对它的引用设置如下:
<TabSet @ref="tabSet">
...
</TabSet>
@code {
private TabSet tabSet;
...
}
在 OnAfterRenderAsync 方法中,我为事件分配处理程序:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
tabSet.TabChanged += TabChanged;
}
}
页面第一次呈现时,出现 System.NullReferenceException:对象引用未设置为对象实例的错误。
如果我切换为使用后续渲染,则效果很好:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(!firstRender)
{
tabSet.TabChanged += TabChanged;
}
}
但是当然这很草率,我将在渲染期间触发多个事件处理程序,以触发它们。
如何在第一次渲染时一次分配参考?我正在按照here
的说明操作文档编辑
这是TabSet.razor文件:
@using Components.Tabs
<!-- Display the tab headers -->
<CascadingValue Value="this">
<ul class="nav nav-tabs">
@ChildContent
</ul>
</CascadingValue>
<!-- Display body for only the active tab -->
<div class="nav-tabs-body" style="padding:15px; padding-top:30px;">
@activetab?.ChildContent
</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
public ITab activetab { get; private set; }
public event action TabChanged;
public void AddTab(ITab tab)
{
if (activetab == null)
{
Setactivetab(tab);
}
}
public void Removetab(ITab tab)
{
if (activetab == tab)
{
Setactivetab(null);
}
}
public void Setactivetab(ITab tab)
{
if (activetab != tab)
{
activetab = tab;
NotifyStateChanged();
StateHasChanged();
}
}
private void NotifyStateChanged() => TabChanged?.Invoke();
}
TabSet也使用Tab.razor:
@using Components.Tabs
@implements ITab
<li>
<a @onclick="activate" class="nav-link @TitleCssClass" role="button">
@Title
</a>
</li>
@code {
[CascadingParameter]
public TabSet ContainerTabSet { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private string TitleCssClass => ContainerTabSet.activetab == this ? "active" : null;
protected override void OnInitialized()
{
ContainerTabSet.AddTab(this);
}
private void activate()
{
ContainerTabSet.Setactivetab(this);
}
}
和ITab.cs界面
using microsoft.AspNetCore.Components;
namespace PlatformAdmin.Components.Tabs
{
public interface ITab
{
RenderFragment ChildContent { get; }
public string Title { get; }
}
}
它取自史蒂夫·桑德森(Steve Sanderson)的一个例子,here
编辑2
这是调试器,显示在第一次渲染时tabSet为null:
在其他渲染器上也不为空: