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

如何基于过滤属性实时汇总ObservableCollection中元素的指定属性值?

符合ReactiveUI/Dynamic Data规范的实时总和计算实现

需求场景

开发基于ReactiveUI/Dynamic Data框架的MVVM架构UI系统,展示Record列表:

  • 每个Record包含Name、Id、Size、ShouldBeIncluded(布尔值,标记是否纳入统计)属性
  • 用户可通过复选框修改ShouldBeIncluded值
  • 需要实时更新Total属性,始终为ShouldBeIncluded=true的所有Record的Size之和

规范实现代码

using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Diagnostics;
using System.Reactive.Disposables;

namespace ConsoleApp1;

// 数据模型类
public class Record : ReactiveObject
{
    public string Id { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;

    [Reactive]
    public int Size { get; set; } = 0;

    [Reactive]
    public bool ShouldBeIncluded { get; set; } = false;

    public Record(string id, string name, int size)
    {
        Id = id;
        Name = name;
        Size = size;
    }
}

// 视图模型类
public class TestViewModel : ReactiveObject, IDisposable
{
    private readonly SourceCache<Record, string> _recordCache;
    private readonly ReadOnlyObservableCollection<Record> _records;
    private readonly ObservableAsPropertyHelper<int> _total;
    private readonly CompositeDisposable _disposables = new();

    // 供UI绑定的只读列表
    public ReadOnlyObservableCollection<Record> Records => _records;

    // 实时计算的总和,自动更新
    public int Total => _total.Value;

    public TestViewModel()
    {
        // 使用SourceCache作为数据源,比ObservableCollection更适配Dynamic Data场景
        _recordCache = new SourceCache<Record, string>(x => x.Id);

        _recordCache.Connect()
            // 监听每个Record的ShouldBeIncluded和Size属性变化
            .AutoRefresh(x => x.ShouldBeIncluded)
            .AutoRefresh(x => x.Size)
            // 过滤出需要纳入统计的项
            .Filter(x => x.ShouldBeIncluded)
            // 提取Size值用于求和
            .Transform(x => x.Size)
            // 计算总和,初始值为0
            .Sum()
            // 把结果绑定到_total属性,自动通知UI更新
            .ToProperty(this, x => x.Total, out _total, initialValue: 0)
            .DisposeWith(_disposables);

        // 将缓存数据转为只读ObservableCollection供UI绑定
        _recordCache.Connect()
            .Bind(out _records)
            .Subscribe()
            .DisposeWith(_disposables);
    }

    // 添加记录的方法
    public void AddRecord(Record record)
    {
        _recordCache.AddOrUpdate(record);
    }

    public void Dispose()
    {
        _disposables.Dispose();
        _recordCache.Dispose();
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        using var viewModel = new TestViewModel();

        // 添加10条记录,每条Size为5
        for (var i = 0; i < 10; i++)
        {
            viewModel.AddRecord(new Record(i.ToString(), $"Record {i}", 5));
        }

        // 标记3条记录为纳入统计
        viewModel.Records[0].ShouldBeIncluded = true;
        viewModel.Records[3].ShouldBeIncluded = true;
        viewModel.Records[5].ShouldBeIncluded = true;

        // 验证总和是否为15
        Debug.Assert(viewModel.Total == 15);
    }
}

关键实现说明

  • 使用SourceCache替代ObservableCollection:Dynamic Data推荐用SourceCache做数据源,提供更高效的变更跟踪和查询能力
  • AutoRefresh:监听Record的ShouldBeIncluded和Size属性变化,确保属性变更时自动触发重新计算
  • Filter:筛选出ShouldBeIncluded=true的记录
  • Transform:提取需要求和的Size属性
  • Sum():Dynamic Data内置聚合操作,实时计算总和
  • ToProperty:将Observable结果转为ObservableAsPropertyHelper,自动实现INotifyPropertyChanged,符合MVVM规范,无需手动触发属性变更通知
  • 使用CompositeDisposable管理订阅生命周期,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:02:46