簡體   English   中英

Blazor 組件參考 Null 首次渲染

[英]Blazor Component Reference Null on First Render

我有一個自定義組件,其中包含一個名為 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 引用未設置為 object 錯誤的實例

如果我切換到使用后續渲染它工作正常:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if(!firstRender)
    {
        tabSet.TabChanged += TabChanged;
    }       
}

但當然這是草率的,我將在渲染期間觸發多個事件處理程序。

如何在第一次渲染時一次性分配參考? 我正在關注此處概述的文檔

編輯

這是 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) 的示例,可在此處找到

編輯 2

這是第一次渲染時顯示 tabSet 為 null 的調試器:

在此處輸入圖像描述

而不是 null 附加渲染:

在此處輸入圖像描述

正如Dani Herrera在評論中指出的那樣,這可能是由於組件帶有 if/else 語句,確實如此。 以前,如果 object 是 null,我會隱藏該組件:

@if(Account != null)
{
    <TabSet @ref="tabSet">
     ...
    </TabSet>
}

為了簡潔起見,我忽略了這一點,並做出了錯誤的假設,即問題不是有條件的。 我在第一次渲染時非常錯誤,object 是 null,因此該組件不存在。 所以要小心:我通過將條件移動到組件內的部分來解決它:

<TabSet @ref="tabSet">
    @if(Account != null)
    {
        <Tab>
         ...
        </Tab>
        <Tab>
         ...
        </Tab>
    }
</TabSet>

在第一次渲染中,組件被渲染。 第一次渲染后,引用 object 是指組件。 因此,第一次,組件的 ref 為空(不是 ref)。 有關更多詳細信息,blazor 文檔是此處的詳細問題

tabSet 變量僅在組件被渲染並且其 output 包含 TabSet 元素后才被填充。 在那之前,沒有什么可以參考的。 要在組件完成渲染后操作組件引用,請使用 OnAfterRenderAsync 或 OnAfterRender 方法。

在我的情況下,它通過初始化 object 來解決

例如:私有 TabSet tabSet = new TabSet();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM