【发布时间】:2020-03-08 18:21:26
【问题描述】:
我有一个自定义组件,其中包含一个名为 TabChanged 的事件操作。在我的 Razor 页面中,我设置了对它的引用,如下所示:
<TabSet @ref="tabSet">
...
</TabSet>
@code {
private TabSet tabSet;
...
}
在 OnAfterRenderAsync 方法中,我为事件分配了一个处理程序:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
tabSet.TabChanged += TabChanged;
}
}
第一次呈现页面时,我收到 System.NullReferenceException: Object reference not set to an instance of an object 错误。
如果我切换到使用后续渲染,它可以正常工作:
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 的调试器:
并且在其他渲染中不为空:
【问题讨论】:
-
我试过你的代码,但是在使用
if(firstRender) { tabSet.TabChanged += TabChanged; }时我没有得到一个空异常。TabChanged是代表吗?你能告诉我们一种重现的方法吗? -
感谢您测试 itminus。我更新了我的问题以包含 TabSet 组件文件。它取自史蒂夫·桑德森 (Steve Sanderson) 的示例:gist.github.com/SteveSandersonMS/… 但我添加了该事件。
-
我使用您的代码创建了一个 blazor 客户端项目和一个 blazor 服务器端项目。但是,它对我来说效果很好。见screenshot。我不知道缺少什么?
-
也不确定。我再次运行它并使用在第一次和其他渲染期间显示调试器的屏幕截图更新了我的问题。 tabSet 在第一次渲染后为 null,但在下一次渲染时不为 null!
-
你的
<TabSet @ref="tabSet">在里面和if (吗?
标签: c# asp.net-core blazor blazor-client-side