如何在 ReactiveUI、C# 中将一个可观察对象的反应列表动态合并到一个可观察对象中

How to dynamically merge a reactivelist of observables into one observable in ReactiveUI, C#

我正在尝试使用 ReactiveUI 来制定一些可观察对象。虽然有些东西已经运行良好,但我仍然无法为其他东西找到合适的 ReactiveUI 方法。我还是 ReactiveUI 的新手。

public class ViewModel : ReactiveObject {
    public ReactiveList<A> aList {get;}
}

public class A : ReactiveObject {
    public ReactiveList<B> bList {get;}
}

public class B : ReactiveObject {
    //some properties
}

我有一个ReactiveListaList。它的项目是 ReactiveObject class A,其中包含另一个 ReactiveList bListbList 项为 属性,共 ReactiveObject class B。 从 aList 开始,我如何应对 aListbList 及其所有属性中的任何更改?

我正在尝试这样的事情:

Observable.Merge(viewModel.aList.Select(x => Observable.Merge(x.bList.Select(y => y.Changed))))

但是,当执行此代码时,这只会观察 B 中已经存在的变化。有什么东西可以自动观察 aListbList 的变化并订阅新项目吗?

或者 Observable.Merge 可以观看 ReactiveList 并自动订阅任何新项目并取消订阅已删除的项目吗?

我知道,我可以手动完成,但这可能不会按照预期的方式使用 ReactiveUI。有什么想法吗?

ReactiveList 上的 Changed 属性 会在列表更改时通知您。使用它来了解何时更新订阅以包含 ReactiveLists.

中的更改

要获得每次 ReactiveList<A>ReactiveList<B> 变化时滴答作响的 observable,您可以这样做:

aList.Changed
    .Select(change => Observable.Merge(viewModel.aList.Select(x => Observable.Merge(x.bList.Select(y => y.Changed)))) // Create observable to notify when the sub collections change
        .StartWith(change) // Send the notification that aList has changed immediately
        )
    .Switch() // Only subscribe to the latest change notifications from the sub collections in the most recent aList
    .Subscribe(changes => { /* Do something */});

除了使用 ReactiveList,您还可以尝试我们的库 ReactiveCompositeCollections,它允许您使用 LINQ 展平可观察集合。

public class ViewModel : ReactiveObject {
    public ICompositeSourceList<A> aList {get;}
}

public class A : ReactiveObject {
    public ICompositeSourceList<B> bList {get;}
}

public class B : ReactiveObject {
    //some properties
}

然后

ViewModel vm = ... ;

IComposteList<B> all = 
    from aItem in vm.aList
    from bItem in aItem.bList
    select bItem;

// Subscribe to the stream of flattened items
all.Items.Subscribe((ImmutableList<B> bItems)=>DoSometing(bItems));

// or create an INPC object with a property Items
using(var s = allLines.Subscribe()){
   RenderLines(s.Items);
}

好消息是,这不是基于 IEnumerable 的 LINQ,而是基于 ICompositeCollection 的 LINQ,其中 ICompositeCollection 是一个反应性集合。源列表中的任何更改都会反应性地投射到结果列表中。

内部结构都使用不可变列表,因此对于大型集合,性能可能是个问题。

可以通过

将 ICompositeCollection 转换为 WPF 可用的 ObservableCollection
ObservableCollection<B> observableBs =
   all.CreateObservableCollection(EqualityComparer<B>.Default)

更多详情请见 https://github.com/Weingartner/ReactiveCompositeCollections#using-icompositecollection-with-wpf