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))); } }
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); } }
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); } })); }
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); } })); }
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))); } }