Esempio n. 1
0
        /// <summary>
        /// Creates a collection based on an an Observable by adding items
        /// provided until the Observable completes, optionally ensuring a
        /// delay. Note that if the Observable never completes and withDelay is
        /// set, this method will leak a Timer. This method also guarantees that
        /// items are always added via the UI thread.
        /// </summary>
        /// <param name="fromObservable">The Observable whose items will be put
        /// into the new collection.</param>
        /// <param name="withDelay">If set, items will be populated in the
        /// collection no faster than the delay provided.</param>
        /// <returns>A new collection which will be populated with the
        /// Observable.</returns>
        public static ReactiveCollection <T> CreateCollection <T>(
            this IObservable <T> fromObservable,
            TimeSpan?withDelay = null)
        {
            var ret = new ReactiveCollection <T>();

            if (withDelay == null)
            {
                fromObservable.ObserveOn(RxApp.DeferredScheduler).Subscribe(ret.Add);
                return(ret);
            }

            // On a timer, dequeue items from queue if they are available
            var queue      = new Queue <T>();
            var disconnect = Observable.Timer(withDelay.Value, RxApp.DeferredScheduler)
                             .Subscribe(_ => {
                if (queue.Count > 0)
                {
                    ret.Add(queue.Dequeue());
                }
            });

            // When new items come in from the observable, stuff them in the queue.
            // Using the DeferredScheduler guarantees we'll always access the queue
            // from the same thread.
            fromObservable.ObserveOn(RxApp.DeferredScheduler).Subscribe(queue.Enqueue);

            // This is a bit clever - keep a running count of the items actually
            // added and compare them to the final count of items provided by the
            // Observable. Combine the two values, and when they're equal,
            // disconnect the timer
            ret.ItemsAdded.Scan(0, ((acc, _) => acc + 1)).Zip(fromObservable.Aggregate(0, (acc, _) => acc + 1),
                                                              (l, r) => (l == r)).Where(x => x).Subscribe(_ => disconnect.Dispose());

            return(ret);
        }