问题 使用比原始元素更多的元素创建ReactiveUI派生集合


是否可以创建一个ReactiveUI派生集合,其中包含的元素多于原始集合?

我已经看到有一种过滤集合和选择单个属性的方法,但我正在寻找的是相当于枚举的SelectMany操作。

为了说明这一点,想象一下,试图得到一个派生的集合来代表每个遇到堵车的乘客。

class Car 
{
    ReactiveCollection<Passenger> Passengers;
}

var TrafficJam=new ReactiveCollection<Car>();
EveryPassengerInTheTrafficJam=Cars.CreateDerivedCollection(c=>c.Passengers);

以上不起作用,我认为错误是 IEnumerable<ReactiveCollection<Passenger>> 无法施展 ReactiveCollection<Passenger>  - 无论如何,或类型的东西。

我无法弄清楚这种扁平化的正确方法 - 诚然,我可能在这里完全错误地吠叫,所以如果有更好的方法来实现同样的事情,请告诉我!


1284
2018-03-06 18:04


起源



答案:


在这一刻, CreateDerivedCollection 不支持 SelectMany 作为一种转变,处理删除过于棘手。如果您没有多个项目,则每次都可以重新生成集合:

cars.Changed
    .Select(_ => cars.SelectMany(x => x.Passengers).ToList())
    .ToProperty(this, x => x.Passengers);

编辑: 好的,我们走了:

var whenCarsOrPassengersInThoseCarsChange = Observable.Merge(
    cars.Changed
        .SelectMany(_ =>
            cars.Select(x => x.Passengers.Changed).Merge())
        .Select(_ => Unit.Default),
    cars.Changed.Select(_ => Unit.Default));

whenCarsOrPassengersInThoseCarsChange.StartWith(Unit.Default)
    .Select(_ => cars.SelectMany(x => x.Passengers).ToList())
    .ToProperty(this, x => x.Passengers);

因此,我们的想法是,当我们想要重新评估乘客名单时,我们有两个主要情况:

  1. 当其中一名乘客换上车时
  2. 当其中一辆车改变时

然而,棘手的部分是, 我们只想在集合中观看乘客的汽车 (如果拆除汽车,我们不再关心其乘客)。

正确跟踪自杀乘客

因此,奇怪的SelectMany的想法是,“每次汽车列表更改时,构建一个新的Observable列表,表示乘客收集何时更改,并将它们合并在一起”。

但是,如果我们 只要 有了这个声明,我们将不得不等待添加汽车  在我们得到一个新的旅客名单之前,它的乘客会发生变化,因此我们也必须在车辆清单发生变化时进行更新。

什么是“单位”业务?

在这种情况下,我实际上并不关心这些Observable所发布的值,就在它们发生时。 “Unit”是void的Rx版本,它只有一个值“Unit.Default”。当你只关心事情发生时,你使用它,而不是它的价值。


13
2018-03-07 01:10



这个问题的一个副作用是现在我要去了解你的框架是如何工作的。 :) - JerKimball
因此,简单版本不起作用的原因是 cars.SelectMany 返回一个 IEnumerable (一个 SelectManyEnumerable 或某事),而不是类似的类型 ObservableCollection。没有办法 CreateDerivedCollection 弄清楚如何观看这个集合,所以它最初会填充但不会更新为 cars 已添加/删除项目 - Paul Betts
@PaulBetts理想情况下,我想重新计算汽车中的乘客收集何时发生变化(有人出于绝望,Everybody Hurts风格),或者当汽车收集发生变化时(一辆新车到达交通堵塞),但是 不 在汽车的其他属性上(如果WindscreenWipersEnabled变为真,我不想重新计算EveryPassengerInTheTrafficJam!)。这可能吗? - Daniel Neal
绝对是@JerKimball!我是一个完整的ReactiveUI(和反应式编程)新手,但从我到目前为止看到的,它是 非常 凉。我喜欢它如何能够以声明的方式描述用户界面的整个行为。 - Daniel Neal
喜欢编辑,这正是我想要的:) - Daniel Neal


答案:


在这一刻, CreateDerivedCollection 不支持 SelectMany 作为一种转变,处理删除过于棘手。如果您没有多个项目,则每次都可以重新生成集合:

cars.Changed
    .Select(_ => cars.SelectMany(x => x.Passengers).ToList())
    .ToProperty(this, x => x.Passengers);

编辑: 好的,我们走了:

var whenCarsOrPassengersInThoseCarsChange = Observable.Merge(
    cars.Changed
        .SelectMany(_ =>
            cars.Select(x => x.Passengers.Changed).Merge())
        .Select(_ => Unit.Default),
    cars.Changed.Select(_ => Unit.Default));

whenCarsOrPassengersInThoseCarsChange.StartWith(Unit.Default)
    .Select(_ => cars.SelectMany(x => x.Passengers).ToList())
    .ToProperty(this, x => x.Passengers);

因此,我们的想法是,当我们想要重新评估乘客名单时,我们有两个主要情况:

  1. 当其中一名乘客换上车时
  2. 当其中一辆车改变时

然而,棘手的部分是, 我们只想在集合中观看乘客的汽车 (如果拆除汽车,我们不再关心其乘客)。

正确跟踪自杀乘客

因此,奇怪的SelectMany的想法是,“每次汽车列表更改时,构建一个新的Observable列表,表示乘客收集何时更改,并将它们合并在一起”。

但是,如果我们 只要 有了这个声明,我们将不得不等待添加汽车  在我们得到一个新的旅客名单之前,它的乘客会发生变化,因此我们也必须在车辆清单发生变化时进行更新。

什么是“单位”业务?

在这种情况下,我实际上并不关心这些Observable所发布的值,就在它们发生时。 “Unit”是void的Rx版本,它只有一个值“Unit.Default”。当你只关心事情发生时,你使用它,而不是它的价值。


13
2018-03-07 01:10



这个问题的一个副作用是现在我要去了解你的框架是如何工作的。 :) - JerKimball
因此,简单版本不起作用的原因是 cars.SelectMany 返回一个 IEnumerable (一个 SelectManyEnumerable 或某事),而不是类似的类型 ObservableCollection。没有办法 CreateDerivedCollection 弄清楚如何观看这个集合,所以它最初会填充但不会更新为 cars 已添加/删除项目 - Paul Betts
@PaulBetts理想情况下,我想重新计算汽车中的乘客收集何时发生变化(有人出于绝望,Everybody Hurts风格),或者当汽车收集发生变化时(一辆新车到达交通堵塞),但是 不 在汽车的其他属性上(如果WindscreenWipersEnabled变为真,我不想重新计算EveryPassengerInTheTrafficJam!)。这可能吗? - Daniel Neal
绝对是@JerKimball!我是一个完整的ReactiveUI(和反应式编程)新手,但从我到目前为止看到的,它是 非常 凉。我喜欢它如何能够以声明的方式描述用户界面的整个行为。 - Daniel Neal
喜欢编辑,这正是我想要的:) - Daniel Neal


嗯......我不是那么熟悉ReactiveUI,但只是通过阅读,看起来你需要改变你的位置 SelectMany 去:

var jam = cars.SelectMany(x => x.Passengers).CreateDerivedCollection(p => p);

2
2018-03-06 22:29



这不起作用,但如果确实如此会很好! - Paul Betts