我正在研究一个系统,该系统具有一个列表中显示的记录列表。
每个条目有以下属性:
<<ul>一个布尔值,指示是否应该包含该项目。用户可以选中复选框,将该项的布尔值从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中执行此操作,因此您可以请求计算TotalSize
和NotifyPropertyChanged(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