我们有一个实现Thing
的课程IObservable<Thing>
。在另一个类中,有一个Thing
的集合,该类需要以统一的方式对来自所有这些可观察对象的更新做出反应。显而易见的方法是Observable.Merge()
,这通常有效; 然而,当集合发生变化时,我们还需要订阅我们合并订阅中的任何新Thing
(理论上取消订阅所有已删除的订阅,但这似乎不那么成问题 - 他们只是不会再产生任何更新了。)
我们目前通过在集合的每次更改时重新创建订阅来实现这一目标,但这在处理开销方面似乎相当不理想,而且由于在丢弃之间的短暂时间内缺少任何Thing
的更新旧订阅并创建新订阅(事实证明这是一个问题,特别是因为我们还需要在短时间内Buffer()
订阅,并且在处理订阅时丢失缓冲的项目)
合并这样一个不断变化的可观察集合的正确方法是什么?
答案 0 :(得分:1)
如果你有一个IObservable<IObservable<T>> observable
,那么就打电话给Merge
就会包括新父母的孩子,如果你抓住了我的漂移。诀窍是将ObservableCollection<IObservable<Thing>>
转换为IObservable<IObservable<Thing>>
。
如果您正在运行ReactiveUI,并且可以使用它,那么您可以将ObservableCollection<IObservable<Thing>>
转换为ReactiveCollection<IObservable<Thing>>
。 ReactiveCollection
继承自ObservableCollection
,并且还实现了IObservable
。
如果ReactiveUI是不可能的(我猜这是因为你已经在使用Caliburn Micro集合),那么你可以使用ObservableCollection
的事件进行转换:
ObservableCollection<IObservable<Thing>> observableCollection = new ObservableCollection<IObservable<Thing>>();
IObservable<IObservable<Thing>> oCollectionObservable = Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
h => observableCollection.CollectionChanged += h,
h => observableCollection.CollectionChanged -= h
)
.SelectMany(ep => ep.EventArgs.NewItems.Cast<IObservable<Thing>>());
以下是一些演示用法的示例代码:
oCollectionObservable
.Merge()
.Subscribe(t => Console.WriteLine($"Received Thing {{Id = {t.Id}}}"));
var firstObservable = Observable.Range(1, 5)
.Select(i => new Thing { Id = i })
.Concat(
Observable.Range(8, 5)
.Select(i => new Thing { Id = i })
.Delay(TimeSpan.FromSeconds(2))
);
observableCollection.Add(firstObservable);
var subject = new Subject<Thing>();
observableCollection.Add(subject);
subject.OnNext(new Thing { Id = 6 });
subject.OnNext(new Thing { Id = 7 });
使用以下课程:
public class Thing
{
public int Id { get; set; }
}