问题描述
我有一个自定义组件,带有一个名为TabChanged的事件Action.在我的Razor页面中,我将对它的引用设置如下:
< TabSet @ ref ="tabSet">...</TabSet>@代码 {私有TabSet tabSet;...}
在 OnAfterRenderAsync 方法中,我为事件分配处理程序:
受保护的重写异步任务OnAfterRenderAsync(bool firstRender){如果(firstRender){tabSet.TabChanged + = TabChanged;}}
页面第一次呈现时,出现 System.NullReferenceException:对象引用未设置为对象实例的错误.
如果我切换为使用后续渲染,则效果很好:
受保护的重写异步任务OnAfterRenderAsync(bool firstRender){如果(!firstRender){tabSet.TabChanged + = TabChanged;}}
但是,这当然是草率的,我将在渲染期间触发多个事件处理程序,以触发它们.
如何在第一次渲染时一次分配参考?我正在按照
在其他渲染器上不为空:
如 Dani Herrera 所述评论这可能是由于组件带有if/else语句而确实如此.以前,如果对象为null,我会将组件隐藏起来:
@if(帐户!=空){< TabSet @ ref =" tabSet">...</TabSet>}
为简洁起见,我忽略了这一点,并错误地认为该问题不是有条件的.我非常错误,因为在第一次渲染时该对象为null,因此该组件不存在!所以要小心.我通过将条件转移到组件中的各个部分来解决了该问题:
< TabSet @ ref =" tabSet">@if(帐户!=空){< Tab>...</Tab>< Tab>...</Tab>}</TabSet>
I have a custom component with an event Action called TabChanged. In my Razor page I set the reference to it up like so:
<TabSet @ref="tabSet">
...
</TabSet>
@code {
private TabSet tabSet;
...
}
In the OnAfterRenderAsync method I assign a handler to the event:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
tabSet.TabChanged += TabChanged;
}
}
The first time the page renders I get a System.NullReferenceException: Object reference not set to an instance of an object error.
If I switch to use subsequent renders it works fine:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(!firstRender)
{
tabSet.TabChanged += TabChanged;
}
}
But of course this is sloppy and I will be firing multiple event handlers as they stack up during renders.
How can I assign the reference one time and on first render? I am following the docs as outlined here
EDIT
Here is the TabSet.razor file:
@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 also uses 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);
}
}
And ITab.cs Interface
using Microsoft.AspNetCore.Components;
namespace PlatformAdmin.Components.Tabs
{
public interface ITab
{
RenderFragment ChildContent { get; }
public string Title { get; }
}
}
It's taken from a Steve Sanderson example found here
EDIT 2
Here is the debugger showing tabSet is null on first render:
And not null on additional renders:
As Dani Herrera pointed out in the comments this may be due to the component being withing an if/else statement and indeed it was. Previously I had the component hidden if an object was null:
@if(Account != null)
{
<TabSet @ref="tabSet">
...
</TabSet>
}
I left this out for brevity and made the incorrect assumption that the issue was not the conditional. I was very wrong as on first render the object is null and therefore the component does not exist! So be careful out there. I resolved it by moving my conditionals to the sections within the component:
<TabSet @ref="tabSet">
@if(Account != null)
{
<Tab>
...
</Tab>
<Tab>
...
</Tab>
}
</TabSet>
这篇关于首次渲染时Blazor组件参考为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!