如何根据每个元素的过滤器属性从ObservableCollection中的每个元素求和属性?



我正在研究一个系统,该系统具有一个列表中显示的记录列表。

每个条目有以下属性:

<<ul>
  • 名称/gh>
  • Id
  • 大小
  • 一个布尔值,指示是否应该包含该项目。用户可以选中复选框,将该项的布尔值从false更改为true。等。

    基于用户更改各种项目的复选框,我需要保留一个"TotalSize">最新属性以便它反映列表中所有项目的大小属性的总和,其中项目的"shouldbeinclded"属性为true。

    我试图在一个基于UI的应用程序运行ReactiveUI/动态数据。

    我在我做的所有事情中使用MVVM方法。所以我不想把这段代码直接绑定到我的视图层。

    为了这个问题的目的,我已经将这一切简化为一个简单的复制。

    我想我需要在ObservableCollection上观察属性变化,但我不知道如何将其绑定回ReactiveUI属性。

    • 我已经尝试了各种动态数据方法,包括那些我已经注释掉。
    • 我已经尝试过ObservableAsAProperty helper
    • 我已经尝试手动执行

    但是我想了解最习惯的方法来做到这一点,但是我所做的一切似乎都使它过于复杂。

    下面是一些样板代码,显示了我在哪里:

    using DynamicData;
    using DynamicData.Binding;
    using ReactiveUI;
    using ReactiveUI.Fody.Helpers;
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    namespace ConsoleApp1;
    /** Simplified for this question, but let's say I'm building a UI with this layout
    * | Name    | Should be Included| Size |
    * | Record 1| [ ]               |5     |
    * | Record 2| [ ]               |5     |
    * ... etc.
    * 
    * Total: the sum of items' size where their "Should be included" checkbox is true
    */
    
    // For some boilerplate code here we go
    // Our "Record" which has the properties from the table above
    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;
    }
    }
    // A "View Model" that can be used to display them
    public class Test
    {
    public ObservableCollection<Record> records;
    // How do I keep Total up to date with the correct value, in this case 15?
    public int Total { get; set; }
    public Test()
    {
    records = new ObservableCollection<Record>();
    //records.ToObservableChangeSet(x => x.Id).Filter(x=> x.ShouldBeIncluded). What's next? Is this right?;
    }
    }
    public class Program
    {
    public static void Main(string[] args)
    {
    // Create a new test object
    var t = new Test();
    // Add 10 records to it, each with a size of 5
    for (var i = 0; i < 10; i++)
    {
    t.records.Add(new Record(i.ToString(), $"Record {i}", 5));
    }
    // Mark 3 records as needing to be "Included"
    t.records[0].ShouldBeIncluded = true;
    t.records[3].ShouldBeIncluded = true;
    t.records[5].ShouldBeIncluded = true;
    Debug.Assert(t.Total == 15);
    }
    }
    

    你也可以在GH上找到一个最小复制Avalonia应用程序:https://github.com/ProbablePrime/Repro-ReactiveUI-MVVM-Sum-Filter

  • 由于您是在UI中执行此操作,因此您可以请求计算TotalSizeNotifyPropertyChanged(TotalSize)

    如果你想通过改变布尔值来实现它,你的模型应该在属性的setter中实现NotifyProperyChanged

    无论如何,你的代码没有计算TotalSize(正如Debug.Assert所指出的)。我会使用@Pieterjan的建议来计算:public int Total => records.Where(r => r.ShouldBeIncluded).Select(r => r.Size).Sum();

    我在Avalonia讨论区问过同样的问题。

    用户名:alxgenov

    提供了一个完美的基于DynamicData的答案!

    private ObservableAsPropertyHelper<int> total;
    public int Total => total.Value;
    // In constructor
    total = Records
    .ToObservableChangeSet(x => x.Id) 
    .AutoRefresh(x => x.ShouldBeIncluded)
    .Filter(x => x.ShouldBeIncluded)
    .Sum(x => x.Size)
    .ToProperty(this, x => x.Total);
    

    这将使Total作为Avalonia可以绑定的ObservableProperty保持最新。

    谢谢大家的帮助!

    你可以在下面的示例应用中看到它的实现:https://github.com/ProbablePrime/Repro-ReactiveUI-MVVM-Sum-Filter/commit/55d1042e52a5da6f773e0dc37f099226e27b9829

    最新更新