public static ReadOnlyDictionarySubject <TKey, TValue> Collect <TKey, TValue>(this IObservable <CollectionModification <KeyValuePair <TKey, TValue> > > source) { Contract.Requires(source != null); Contract.Ensures(Contract.Result <ReadOnlyDictionarySubject <TKey, TValue> >() != null); var subscription = new SingleAssignmentDisposable(); var dictionary = new DictionarySubject <TKey, TValue>(subscription); subscription.Disposable = source.Subscribe(dictionary); return(new ReadOnlyDictionarySubject <TKey, TValue>(dictionary)); }
/// <summary> /// Adds the elements from the specified observable sequence into a <see cref="ReadOnlyDictionarySubject{TKey,TValue}"/>. /// </summary> /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam> /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam> /// <param name="source">The sequence from which elements are collected.</param> /// <param name="keySelector">A function that maps values to keys.</param> /// <returns>A <see cref="ReadOnlyDictionarySubject{TKey,TValue}"/> that receives the elements from the specified sequence.</returns> public static ReadOnlyDictionarySubject <TKey, TValue> Collect <TKey, TValue>(this IObservable <TValue> source, Func <TValue, TKey> keySelector) { Contract.Requires(source != null); Contract.Requires(keySelector != null); Contract.Ensures(Contract.Result <ReadOnlyDictionarySubject <TKey, TValue> >() != null); var subscription = new SingleAssignmentDisposable(); var dictionary = new DictionarySubject <TKey, TValue>(subscription); subscription.Disposable = source.Subscribe(value => dictionary[keySelector(value)] = value, dictionary.OnError, dictionary.OnCompleted); return(new ReadOnlyDictionarySubject <TKey, TValue>(dictionary)); }
protected override void Main() { var source = new DictionarySubject <string, CustomValue>(); var monitorKeys = new[] { "A", "C", "D", "E", "F", "G" }; // PropertyChanges doesn't work on KeyValuePair because it doesn't have any property change events. // So we must strip off the key and create a sequence of collection notifications for the values only. using (source .Where( exists: _ => false, onAdded: added => monitorKeys.Contains(added.Key), onReplaced: (replaced, added) => monitorKeys.Contains(replaced.Key) && monitorKeys.Contains(added.Key), onRemoved: removed => monitorKeys.Contains(removed.Key), onCleared: () => false) .Select( _ => null, added => CollectionNotification.CreateOnAdded(added.Value), (replaced, added) => CollectionNotification.CreateOnReplaced(replaced.Value, added.Value), removed => CollectionNotification.CreateOnRemoved(removed.Value), () => null) .PropertyChanges() .Select(e => new { Object = (CustomValue)e.Sender, Property = e.EventArgs.PropertyName }) .Subscribe(value => TraceLine("Changed {0}: {1}", value.Property, value.Object))) { var a = new CustomValue("A"); var b = new CustomValue("B"); var c = new CustomValue("C"); source.Add(a.Name, a); source.Add(b.Name, b); source.Add(c.Name, c); a.Child = new CustomValue("D"); b.Child = new CustomValue("E"); c.Child = new CustomValue("F"); a.Child.Child = new CustomValue("G"); a.Number = 1; b.Number = 1; c.Number = 1; a.Child.Number = 100; b.Child.Number = 101; c.Child.Number = 102; var child = a.Child; var grandchild = child.Child; grandchild.Number = 103; child.Child = null; grandchild.Number = 104; child.Number = 105; a.Child = null; child.Number = 106; source.Remove(a.Name); a.Number = 2; b.Number = 2; c.Number = 2; child.Number = 200; b.Child.Number = 201; c.Child.Number = 202; grandchild.Number = 203; source.Remove(b.Name); source.Remove(c.Name); a.Number = 4; b.Number = 4; c.Number = 4; child.Number = 300; b.Child.Number = 301; c.Child.Number = 302; grandchild.Number = 303; } }