예제 #1
0
        public static IObservable <IChangeSet <TObject> > DelayRemove <TObject>(this IObservable <IChangeSet <TObject> > source,
                                                                                TimeSpan delayPeriod, Action <TObject> onDefer)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (onDefer == null)
            {
                throw new ArgumentNullException("onDefer");
            }

            return(Observable.Create <IChangeSet <TObject> >(observer =>
            {
                var removed = new [] { ListChangeReason.Remove, ListChangeReason.Clear, ListChangeReason.RemoveRange };

                var localList = new SourceList <TObject>();

                var locker = new object();
                var shared = source.Synchronize(locker).Publish();

                var notRemoved = shared.WhereReasonsAreNot(removed)
                                 .Subscribe(changes =>
                {
                    localList.Edit(innerList =>
                    {
                        changes.ForEach(change =>
                        {
                            switch (change.Reason)
                            {
                            case ListChangeReason.Add:
                                innerList.Add(change.Item.Current);
                                break;

                            case ListChangeReason.AddRange:
                                change.Range.ForEach(innerList.Add);
                                break;

                            case ListChangeReason.Replace:
                                innerList.Replace(change.Item.Previous.Value, change.Item.Current);
                                break;
                            }
                        });
                    });
                });

                //when removed,invoke call back
                var removes = shared.WhereReasonsAre(removed)
                              .ForEachItemChange(change => onDefer(change.Current))
                              .Delay(delayPeriod)
                              .Synchronize(locker)
                              .Subscribe(changes =>
                {
                    //flatten removes into a single enumerable
                    var toRemove = changes.SelectMany(change =>
                    {
                        return change.Type == ChangeType.Item ? new[] { change.Item.Current } : change.Range.Select(t => t);
                    });
                    //remove in one hit
                    localList.RemoveMany(toRemove);
                });

                var subscriber = localList.Connect().SubscribeSafe(observer);
                return new CompositeDisposable(subscriber, removes, notRemoved, shared.Connect());
            }));
        }