/// <summary> /// Gets or sets the element at the specified index. /// </summary> /// <param name="index">The zero-based index of the element to get or set.</param> /// <returns>The element at the specified index.</returns> /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the list.</exception> public T this[int index] { get { lock (gate) { EnsureNotDisposed(); EnsureNotFaulted(); Contract.Assume(index < list.Count); return(list[index]); } } set { lock (gate) { EnsureNotDisposed(); if (EnsureNotStopped()) { Contract.Assume(index < list.Count); T previous = list[index]; list[index] = value; subject.OnNext(CollectionNotification.CreateOnReplaced(previous, value)); } } } }
private void SetInternal(KeyValuePair <TKey, TValue> newPair) { if (dictionary.Contains(newPair.Key)) { int index = dictionary.IndexOf(newPair.Key); Contract.Assume(index >= 0); var oldPair = dictionary[index]; dictionary[index] = newPair; OnPropertyChanged(new PropertyChangedEventArgs("Values")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); #if !PORT_40 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newPair, oldPair, index)); #endif subject.OnNext(CollectionNotification.CreateOnReplaced(oldPair, newPair)); } else { AddInternal(newPair); } }
/// <summary> /// Converts <see cref="INotifyCollectionChanged.CollectionChanged"/> events into an observable sequence of <see cref="CollectionNotification{T}"/>. /// </summary> /// <typeparam name="T">The object that provides notification information.</typeparam> /// <param name="source">An implementation of <see cref="INotifyCollectionChanged"/> that raises events when a collection changes.</param> /// <remarks> /// An <see cref="NotifyCollectionChangedAction.Add"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnAdded"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Remove"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnRemoved"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Move"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnReplaced"/> notifications /// where <see cref="CollectionNotification{T}.Value"/> and <see cref="CollectionNotification{T}.ReplacedValue"/> refer to the same value. /// A <see cref="NotifyCollectionChangedAction.Replace"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnReplaced"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Reset"/> event is projected into a single <see cref="CollectionNotificationKind.OnCleared"/> notification. /// </remarks> /// <returns>An observable sequence of <see cref="CollectionNotification{T}"/> objects corresponding to raised events.</returns> #else /// <summary> /// Converts <see cref="INotifyCollectionChanged.CollectionChanged"/> events into an observable sequence of <see cref="CollectionNotification{T}"/>. /// </summary> /// <typeparam name="T">The object that provides notification information.</typeparam> /// <param name="source">An implementation of <see cref="INotifyCollectionChanged"/> that raises events when a collection changes.</param> /// <remarks> /// An <see cref="NotifyCollectionChangedAction.Add"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnAdded"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Remove"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnRemoved"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Replace"/> event is projected into zero or more <see cref="CollectionNotificationKind.OnReplaced"/> notifications. /// A <see cref="NotifyCollectionChangedAction.Reset"/> event is projected into a single <see cref="CollectionNotificationKind.OnCleared"/> notification. /// </remarks> /// <returns>An observable sequence of <see cref="CollectionNotification{T}"/> objects corresponding to raised events.</returns> #endif public static IObservable <CollectionNotification <T> > AsCollectionNotifications <T>(this INotifyCollectionChanged source) { Contract.Requires(source != null); Contract.Ensures(Contract.Result <IObservable <CollectionNotification <T> > >() != null); return(Observable.FromEventPattern <NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>( eh => source.CollectionChanged += eh, eh => source.CollectionChanged -= eh) .SelectMany(e => { var args = e.EventArgs; switch (args.Action) { case NotifyCollectionChangedAction.Add: return EnsureSequence <T>(args.NewItems).Select(CollectionNotification.CreateOnAdded).ToObservable(); case NotifyCollectionChangedAction.Remove: return EnsureSequence <T>(args.OldItems).Select(CollectionNotification.CreateOnRemoved).ToObservable(); #if !SILVERLIGHT case NotifyCollectionChangedAction.Move: return EnsureSequence <T>(args.OldItems).Select(value => CollectionNotification.CreateOnReplaced(value, value)).ToObservable(); #endif case NotifyCollectionChangedAction.Replace: return EnsureSequence <T>(args.NewItems) .Zip( EnsureSequence <T>(args.OldItems), (newValue, oldValue) => CollectionNotification.CreateOnReplaced(oldValue, newValue)) .ToObservable(); case NotifyCollectionChangedAction.Reset: return Observable.Return(CollectionNotification.CreateOnCleared <T>()); default: throw new InvalidOperationException(); } })); }
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; } }