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

如何仅在ReactiveCollection中PlayerBuildings指定属性变更时订阅?

精准订阅ReactiveCollection的特定属性变化

当然可以实现!我们可以借助ReactiveExtensions(Rx)的操作符,精准过滤出你关心的两类变化信号,避免不必要的计算和订阅触发。核心思路是只监听与目标资源相关的属性变更,然后在这些变更发生时重新计算生产总和。

关键逻辑拆解

我们需要捕捉三类触发更新的场景:

  1. 任意建筑的ProducedResourceId被设置为myResource(或从myResource改为其他值,因为这也会影响总和)
  2. 已经生产myResource的建筑,其ProductionPerHour发生变化
  3. 集合中添加/移除了生产myResource的建筑(这一步容易被忽略,但同样会影响总和)

伪代码实现(基于ReactiveUI)

假设你的PlayerBuilding是继承自ReactiveObject的响应式对象(这是ReactiveUI的标准做法):

// 定义PlayerBuilding类
public class PlayerBuilding : ReactiveObject
{
    private string _producedResourceId;
    public string ProducedResourceId
    {
        get => _producedResourceId;
        set => this.RaiseAndSetIfChanged(ref _producedResourceId, value);
    }

    private double _productionPerHour;
    public double ProductionPerHour
    {
        get => _productionPerHour;
        set => this.RaiseAndSetIfChanged(ref _productionPerHour, value);
    }
}

// 你的ViewModel中的核心逻辑
public class YourViewModel : ReactiveObject
{
    public ReactiveCollection<PlayerBuilding> PlayerBuildings { get; } = new();
    public string MyResource { get; } = "wood"; // 你的目标资源ID
    private string _textValue;
    public string TextValue
    {
        get => _textValue;
        set => this.RaiseAndSetIfChanged(ref _textValue, value);
    }

    public YourViewModel()
    {
        // 构建只包含我们关心的变化的可观察流
        var relevantChangeSignals = Observable.Merge(
            // 监听集合的添加/移除操作(避免漏掉新加入或移除的目标资源建筑)
            PlayerBuildings.Changed.Select(_ => Unit.Default),
            
            // 遍历集合中每个建筑,监听其关键属性变化
            PlayerBuildings.SelectMany(building => Observable.Merge(
                // 场景1:ProducedResourceId变更,且变更涉及目标资源
                building.WhenAnyValue(b => b.ProducedResourceId)
                    .Skip(1) // 跳过初始值,只处理后续的变更
                    .Where(newId => newId == MyResource || building.ProducedResourceId == MyResource)
                    .Select(_ => Unit.Default),
                
                // 场景2:生产目标资源的建筑,其ProductionPerHour变更
                building.WhenAnyValue(b => b.ProductionPerHour)
                    .Skip(1)
                    .Where(_ => building.ProducedResourceId == MyResource)
                    .Select(_ => Unit.Default)
            ))
        );

        // 订阅信号,计算总和并更新TextValue
        relevantChangeSignals
            .Throttle(TimeSpan.FromMilliseconds(10)) // 可选:防止短时间多次变更导致频繁计算
            .Select(_ => CalculateTotalProduction())
            .Subscribe(total => TextValue = $"总生产:{total:N2}/小时");
    }

    // 计算目标资源的总生产效率
    private double CalculateTotalProduction()
    {
        return PlayerBuildings
            .Where(b => b.ProducedResourceId == MyResource)
            .Sum(b => b.ProductionPerHour);
    }
}

代码说明

  • Observable.Merge:把多个独立的信号流合并成一个统一的流,方便订阅。
  • PlayerBuildings.SelectMany:遍历集合中的每个建筑,为每个建筑创建其属性变化的监听流。
  • Skip(1):跳过属性的初始值,只响应后续的变更操作(避免初始化时的不必要计算)。
  • Where:精准过滤出我们关心的变化场景,确保只有相关变更才会触发总和计算。
  • Throttle:可选操作,用于防抖,避免短时间内多次修改导致频繁计算总和(比如用户快速调整多个建筑的生产效率时)。

如果你的项目没有使用ReactiveUI,只要你的集合和属性支持Rx的可观察特性,核心逻辑是完全通用的——只需要调整属性变更的监听方式即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:16:27