/// <summary> /// Converts a <see cref="CollectionModification{T}"/> to a list of <see cref="CollectionNotification{T}"/>. /// </summary> /// <typeparam name="T">The object that provides modification information.</typeparam> /// <param name="modification">The <see cref="CollectionModification{T}"/> to be converted.</param> /// <returns>A list of <see cref="CollectionNotification{T}"/> containing /// <see cref="CollectionNotificationKind.OnAdded"/> when the specified <paramref name="modification"/> is <see cref="CollectionModificationKind.Add"/>, /// <see cref="CollectionNotificationKind.OnRemoved"/> when the specified <paramref name="modification"/> is <see cref="CollectionModificationKind.Remove"/>, or /// <see cref="CollectionNotificationKind.OnCleared"/> when the specified <paramref name="modification"/> is <see cref="CollectionModificationKind.Clear"/>.</returns> public static IList <CollectionNotification <T> > ToNotifications <T>(this CollectionModification <T> modification) { Contract.Requires(modification != null); Contract.Ensures(Contract.Result <IList <CollectionNotification <T> > >() != null); Contract.Ensures(Contract.Result <IList <CollectionNotification <T> > >().IsReadOnly); var list = new List <CollectionNotification <T> >(); IList <T> values; switch (modification.Kind) { case CollectionModificationKind.Add: values = modification.Values; for (int i = 0; i < values.Count; i++) { list.Add(CollectionNotification.CreateOnAdded <T>(values[i])); } break; case CollectionModificationKind.Remove: values = modification.Values; for (int i = 0; i < values.Count; i++) { list.Add(CollectionNotification.CreateOnRemoved <T>(values[i])); } break; case CollectionModificationKind.Clear: list.Add(CollectionNotification.CreateOnCleared <T>()); break; } IList <CollectionNotification <T> > result = list.AsReadOnly(); Contract.Assume(result.IsReadOnly); return(result); }
/// <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(); } })); }