Blazor StateHasChanged() 不更新页面上的全局 class 值

Blazor StateHasChanged() doesnt update global class values on page

所以我正在尝试实现一个多站点服务器端 blazor 应用程序,其中有两个服务实现为单例,如下所示:

            services.AddSingleton<MQTTService>();
            services.AddHostedService(sp => sp.GetRequiredService<MQTTService>());

            services.AddSingleton<DataCollectorService>();
            services.AddHostedService(sp => sp.GetRequiredService<DataCollectorService>());

MQTT 服务正在连接到代理并管理订阅和内容,而 DataCollectorService 订阅来自 MQTT 服务的事件,以便在新消息到达时收到通知。接收到的数据的业务逻辑随后在 DataCollectorService 中发生,比如解释主题和 mqtt 消息的有效负载。如果有效,DataCollectorService 将数据存储在(示例)全局静态 class:

            if (mqtt.IsTopic(topic, MQTTService.TopicDesc.FirstTopic))
            {
                if(topic.Contains("Data1"))
                {
                    if(topic.Contains("Temperature"))
                    {
                        DataCenter.Data1.Temperature= Encoding.UTF8.GetString(message, 0, message.Length);
                    }
                }
            }

DataCenter 只是命名空间中的静态 class:

    public static class DataCenter
    {
        public static DataBlock Data1 = new DataBlock();
        public static DataBlock Data2 = new DataBlock();

        public static string SetMode;

        public class DataBlock
        {
            public string Temperature { get; set; }
            public string Name{ get; set; }
        }
    }

我使用这种方法的目标是我项目中的每个不同页面都可以绑定这些全局变量来显示它们。

然后出现的第一个问题是,如果 DataCollectorService 更新变量,页面显然不知道更改。这就是为什么我为页面实现了一个通知事件,然后可以调用 StateHasChanged。所以我的 examplePage“Monitor”只想显示所有这些值并注入 DataCollectorService:

@page "/monitor"
@inject DataCollectorService dcs

<MudText>DataBlock Data1: @DataCenter.Data1.Temperature/ Data2: @DataCenter.Data2.Temperature</MudText>


@code
{
        protected override void OnInitialized()
        {
            dcs.OnRefresh += OnRefresh;
        }

        void OnRefresh()
        {
            InvokeAsync(() =>
            {
                Console.WriteLine("OnRefresh CALLED");
                StateHasChanged();
            });
        }
}

这确实有效,但给 table 添加了一个新问题,每次我再次切换到我的监视站点时,新的 OnRefresh 方法会与操作挂钩,这会导致多次调用“OnRefresh”。我发现这种行为很合乎逻辑,因为当我离开网站时,我从不从操作中删除“旧的”OnRefresh 方法,因为我不知道我什么时候离开网站。 考虑到这个问题,我想到了一个解决方案:

            if (!dcs.IsRegistered("monitor"))
            {
                dcs.OnRefresh += OnRefresh;
                dcs.RegisterSubscription("monitor");
            }

我用一个系统包装了动作订阅,只要处理程序已经正确分配,该系统就会注册令牌。现在的问题:网站上的变量不再刷新了!

这就是我不确定如何理解正在发生的事情的地方。如果我像第一个例子一样保留它,那么只需添加 dcs.OnRefresh += OnRefresh;并让它“堆叠起来”,它确实有效——因为总是有一个“新的”和“正确”绑定的方法,在我有限的理解中,它具有正确的上下文。

如果我禁止这种行为,我只连接了某种“旧”方法,该方法无法正确执行 StateHasChanged。但是不知道为什么。

我不确定我是否可以:

  1. “更改”Invoke Call 的上下文以便 StateHasChanged 再次起作用?
  2. 更改我注册 Action Handling 方法的方式

我还对为什么第一种方法似乎多次调用该方法感到困惑。因为如果在旧方法中不能正确调用StateHasChanged(),为什么一开始就可以调用?

非常感谢这里的一些输入,谷歌搜索这类东西相当困难,因为我不知道问题的确切根源。

你不仅有多次调用,还有内存泄漏。事件订阅将阻止收集 Monitor 对象。

使页面 IDisposable:

@page "/monitor"
@inject DataCollectorService dcs
@implements IDisposable

...

@code
{

   protected override void OnInitialized()
   {
      dcs.OnRefresh += OnRefresh;
   }

   ...

   public void Dispose()
   {
     dcs.OnRefresh -= OnRefresh;
   }
}