private void ProcessIncomingChange(ReactiveSetChange <T> changes)
        {
            // Update the local set first
            lock (this.syncRoot) {
                // Signal observers of the change
                this.subject.OnNext(changes);

                if (changes.ChangeReason == ReactiveSetChangeReason.Add)
                {
                    foreach (var item in changes.Items)
                    {
                        this.list.Add(item);
                    }
                }
                else
                {
                    foreach (var item in changes.Items)
                    {
                        this.list.Remove(item);
                    }
                }

                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Min)));
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Max)));
            }
        }
Beispiel #2
0
        public int AddRange(IEnumerable <T> elements)
        {
            if (elements == null)
            {
                throw new ArgumentNullException(nameof(elements));
            }

            lock (this.syncRoot) {
                // Figure out which items need to be added
                var addedItems = new HashSet <T>();
                foreach (var item in elements)
                {
                    if (!this.set.Contains(item))
                    {
                        addedItems.Add(item);
                    }
                }

                // Produce a change
                var change = new ReactiveSetChange <T>(ReactiveSetChangeReason.Add, addedItems);
                this.changes.OnNext(change);

                // Update the set
                foreach (T item in addedItems)
                {
                    this.set.Add(item);
                }

                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
                return(addedItems.Count);
            }
        }
Beispiel #3
0
        public int RemoveRange(IEnumerable <T> elements)
        {
            if (elements == null)
            {
                throw new ArgumentNullException(nameof(elements));
            }

            lock (this.syncRoot) {
                var removedItems = new HashSet <T>();

                foreach (var item in elements)
                {
                    if (this.set.Contains(item))
                    {
                        removedItems.Add(item);
                    }
                }

                var change = new ReactiveSetChange <T>(ReactiveSetChangeReason.Remove, removedItems);
                this.changes.OnNext(change);

                foreach (T item in removedItems)
                {
                    this.set.Remove(item);
                }

                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
                return(removedItems.Count);
            }
        }
        public IObservable <ReactiveSetChange <T> > AsObservable()
        {
            return(Observable.Create <ReactiveSetChange <T> >(observer => {
                lock (this.syncRoot) {
                    var initial = new ReactiveSetChange <T>(ReactiveSetChangeReason.Add, this.list);
                    observer.OnNext(initial);

                    return this.subject.Subscribe(observer);
                }
            }));
        }
Beispiel #5
0
        public void Clear()
        {
            lock (this.syncRoot) {
                // Update observers
                var change = new ReactiveSetChange <T>(ReactiveSetChangeReason.Remove, this.set);
                this.changes.OnNext(change);

                this.set.Clear();
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
            }
        }
        public IObservable <ReactiveSetChange <TResult> > AsObservable()
        {
            return(Observable.Create <ReactiveSetChange <TResult> >(observer => {
                lock (this.syncRoot) {
                    var change = new ReactiveSetChange <TResult>(ReactiveSetChangeReason.Add, this.counts.Keys);
                    observer.OnNext(change);

                    return this.changes.Subscribe(observer);
                }
            }));
        }
Beispiel #7
0
        public bool Add(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (!this.set.Contains(item))
            {
                lock (this.syncRoot) {
                    // Update observers
                    var change = new ReactiveSetChange <T>(ReactiveSetChangeReason.Add, new[] { item });
                    this.changes.OnNext(change);

                    this.set.Add(item);
                    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));

                    return(true);
                }
            }

            return(false);
        }
        private void ProcessIncomingChanges(ReactiveSetChange <T> change)
        {
            // Update the local set first
            lock (this.syncRoot) {
                ReactiveSetChange <TResult> newChange;

                // Compute new changes
                if (change.ChangeReason == ReactiveSetChangeReason.Add)
                {
                    var addedItems = new List <TResult>();

                    foreach (var item in change.Items)
                    {
                        // We haven't uncountered this item yet
                        if (!this.conversions.ContainsKey(item))
                        {
                            // Convert and store the conversion
                            var selected = this.selector(item);
                            this.conversions[item] = selected;

                            // If we haven't encountered this output before, make sure to produce a change
                            // notification and add it to the counts
                            if (!this.counts.ContainsKey(selected))
                            {
                                addedItems.Add(selected);
                                this.counts[selected] = 0;
                            }

                            this.counts[selected]++;
                        }
                    }

                    newChange = new ReactiveSetChange <TResult>(ReactiveSetChangeReason.Add, addedItems);
                }
                else
                {
                    var removedItems = new List <TResult>();

                    foreach (var item in change.Items)
                    {
                        // We can remove this item
                        if (this.conversions.TryGetValue(item, out var newValue))
                        {
                            // Remove the item
                            this.conversions.Remove(item);

                            // Decrement the count of this output
                            this.counts[newValue]--;

                            // Produce a change notification if we ran out of this output
                            if (this.counts[newValue] == 0)
                            {
                                removedItems.Add(newValue);
                                this.counts.Remove(newValue);
                            }
                        }
                    }

                    newChange = new ReactiveSetChange <TResult>(ReactiveSetChangeReason.Remove, removedItems);
                }

                // Signal observers of the change
                this.changes.OnNext(newChange);
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
            }
        }