You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor(.NET6)中NavMenu无法实时显示Counter计数的问题求助

解决Blazor NavMenu实时显示Counter计数的问题

方法一:使用状态容器服务(推荐,适合跨组件共享状态)

这种方式通过依赖注入共享状态,支持任意组件间同步数据,且能在属性变化时自动通知组件更新。

  1. 创建状态容器类
    新建MenuState.cs,实现INotifyPropertyChanged接口,确保属性变更时触发通知:
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class MenuState : INotifyPropertyChanged
{
    private int _counterValue;

    public int CounterValue
    {
        get => _counterValue;
        set
        {
            if (_counterValue != value)
            {
                _counterValue = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
  1. 注册状态服务
    在Program.cs中添加Scoped生命周期的服务注册:
builder.Services.AddScoped<MenuState>();
  1. 修改Counter.razor注入并更新状态
    注入状态容器,点击按钮时同步更新容器内的计数值:
@page "/counter"
@inject MenuState MenuState

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        MenuState.CounterValue = currentCount;
    }
}
  1. 修改NavMenu.razor订阅状态变化并显示
    注入状态容器,订阅属性变更事件以触发组件重新渲染:
@inject MenuState MenuState
@implements IDisposable

<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">BlazorApp</a>
        <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
                <span class="badge bg-primary ms-2">@MenuState.CounterValue</span>
            </NavLink>
        </div>
    </nav>
</div>

@code {
    private bool collapseNavMenu = true;

    private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }

    protected override void OnInitialized()
    {
        MenuState.PropertyChanged += OnStateChanged;
    }

    private void OnStateChanged(object? sender, PropertyChangedEventArgs e)
    {
        StateHasChanged();
    }

    public void Dispose()
    {
        MenuState.PropertyChanged -= OnStateChanged;
    }
}

方法二:使用级联参数(适合层级较浅的组件结构)

若组件结构为MainLayout包含NavMenu和页面内容(Counter),可通过级联参数直接传递状态:

  1. 在MainLayout.razor中定义并传递级联值
@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <CascadingValue Value="this" Name="LayoutState">
            <NavMenu />
        </CascadingValue>
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
        <article class="content px-4">
            <CascadingValue Value="this" Name="LayoutState">
                @Body
            </CascadingValue>
        </article>
    </main>
</div>

@code {
    private int _counterValue;

    public int CounterValue
    {
        get => _counterValue;
        set
        {
            _counterValue = value;
            StateHasChanged();
        }
    }
}
  1. 修改Counter.razor接收级联参数并更新
@page "/counter"
[CascadingParameter(Name = "LayoutState")]
public MainLayout? LayoutState { get; set; }

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        LayoutState?.CounterValue = currentCount;
    }
}
  1. 修改NavMenu.razor接收级联参数并显示
[CascadingParameter(Name = "LayoutState")]
public MainLayout? LayoutState { get; set; }

<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">BlazorApp</a>
        <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
                <span class="badge bg-primary ms-2">@LayoutState?.CounterValue</span>
            </NavLink>
        </div>
    </nav>
</div>

@code {
    private bool collapseNavMenu = true;

    private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

原方案失效的可能原因

  • 使用对象继承但未实现INotifyPropertyChanged:属性变更时组件无法感知,不会触发重新渲染。
  • EventCallback使用不当:NavMenu属于MainLayout的子组件,Counter是独立页面组件,两者无直接父子关系,EventCallback无法跨层级传递。

内容的提问来源于stack exchange,提问作者Zibix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:25:59