protected void NotifyCollectionModification(string propName, object value, CollectionModification modification) { if (CollectionModified != null) { CollectionModified(this, new CollectionModifiedEventArgs() { PropertyName = propName, Value = value, ModificationType = modification }); } }
/// <summary> /// Changes the list according to the specified collection notification. /// </summary> /// <param name="value">A modification that indicates how the list must be changed.</param> public void OnNext(CollectionModification <T> value) { if (value == null) { throw new ArgumentNullException("value"); } lock (gate) { EnsureNotDisposed(); if (EnsureNotStopped()) { IList <T> values; switch (value.Kind) { case CollectionModificationKind.Add: values = value.Values; for (int i = 0; i < values.Count; i++) { var item = values[i]; list.Add(item); subject.OnNext(CollectionNotification.CreateOnAdded(item)); } break; case CollectionModificationKind.Remove: values = value.Values; for (int i = 0; i < values.Count; i++) { var item = values[i]; if (list.Remove(item)) { subject.OnNext(CollectionNotification.CreateOnRemoved(item)); } } break; case CollectionModificationKind.Clear: list.Clear(); subject.OnNext(CollectionNotification.CreateOnCleared <T>()); break; } } } }
/// <summary> /// Changes the dictionary according to the specified collection modification. /// </summary> /// <param name="value">A modification that indicates how the dictionary must be changed.</param> public void OnNext(CollectionModification <KeyValuePair <TKey, TValue> > value) { if (value == null) { throw new ArgumentNullException("value"); } lock (gate) { EnsureNotDisposed(); if (EnsureNotStopped()) { IList <KeyValuePair <TKey, TValue> > pairs; switch (value.Kind) { case CollectionModificationKind.Add: // value.Accept(this) is not used for additions because it calls the ICollection<KeyValuePair<TKey, TValue>>.Add implementation, which throws if the key already exists. pairs = value.Values; for (int i = 0; i < pairs.Count; i++) { SetInternal(pairs[i]); } break; case CollectionModificationKind.Remove: // value.Accept(this) is not used for removals because it calls the ICollection<KeyValuePair<TKey, TValue>>.Remove implementation, which compares keys and also compares values. pairs = value.Values; for (int i = 0; i < pairs.Count; i++) { var key = pairs[i].Key; if (dictionary.Contains(key)) { RemoveInternal(key); } } break; case CollectionModificationKind.Clear: ClearInternal(); break; } } } }
/// <summary> /// Identifies which items were changed, removed and added to the target collection /// when compared with the imported data and performs the necessary operations for /// the dependent data of the affected elements. /// </summary> /// <param name="importedDataCollection">The imported data collection which is used to update /// the <see cref="targetCollection"/>.</param> /// <param name="sourceFilePath">The source file path.</param> /// <returns>An <see cref="IEnumerable{T}"/> with affected objects.</returns> /// <exception cref="UpdateDataException">Thrown when: /// <list type="bullet"> /// <item>duplicate items are being added to the <see cref="targetCollection"/>;</item> /// <item>duplicate items are found in the <paramref name="importedDataCollection"/>.</item> /// </list> /// </exception> /// <exception cref="ArgumentNullException">Thrown when <paramref name="importedDataCollection"/> /// is <c>null</c>.</exception> /// <exception cref="ArgumentException">Thrown when <paramref name="importedDataCollection"/> contains /// <c>null</c> elements.</exception> private IEnumerable <IObservable> ModifyDataCollection(IEnumerable <TTargetData> importedDataCollection, string sourceFilePath) { TTargetData[] importedObjects = importedDataCollection.ToArray(); var modification = new CollectionModification(targetCollection, importedObjects, equalityComparer); var affectedObjects = new List <IObservable>(); if (modification.HasUpdates()) { affectedObjects.Add(targetCollection); } affectedObjects.AddRange(UpdateData(modification.ObjectsToBeUpdated.Values, importedObjects)); affectedObjects.AddRange(RemoveData(modification.ObjectsToBeRemoved)); targetCollection.Clear(); targetCollection.AddRange(modification.GetModifiedCollection(), sourceFilePath); return(affectedObjects.Distinct(new ReferenceEqualityComparer <IObservable>())); }
/// <summary> /// Converts <see cref="INotifyCollectionChanged.CollectionChanged"/> events into an observable sequence of <see cref="CollectionModification{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="CollectionModificationKind.Add"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Remove"/> event is projected into zero or more <see cref="CollectionModificationKind.Remove"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Move"/> event is ignored. /// A <see cref="NotifyCollectionChangedAction.Replace"/> event is projected into zero or more sequential /// <see cref="CollectionModificationKind.Remove"/> and <see cref="CollectionModificationKind.Add"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Reset"/> event is projected into a single <see cref="CollectionModificationKind.Clear"/> modification. /// </remarks> /// <returns>An observable sequence of <see cref="CollectionModification{T}"/> objects corresponding to raised events.</returns> #else /// <summary> /// Converts <see cref="INotifyCollectionChanged.CollectionChanged"/> events into an observable sequence of <see cref="CollectionModification{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="CollectionModificationKind.Add"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Remove"/> event is projected into zero or more <see cref="CollectionModificationKind.Remove"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Replace"/> event is projected into zero or more sequential /// <see cref="CollectionModificationKind.Remove"/> and <see cref="CollectionModificationKind.Add"/> modifications. /// A <see cref="NotifyCollectionChangedAction.Reset"/> event is projected into a single <see cref="CollectionModificationKind.Clear"/> modification. /// </remarks> /// <returns>An observable sequence of <see cref="CollectionModification{T}"/> objects corresponding to raised events.</returns> #endif public static IObservable <CollectionModification <T> > AsCollectionModifications <T>(this INotifyCollectionChanged source) { Contract.Requires(source != null); Contract.Ensures(Contract.Result <IObservable <CollectionModification <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 Observable.Return(CollectionModification.CreateAdd(EnsureList <T>(args.NewItems))); case NotifyCollectionChangedAction.Remove: return Observable.Return(CollectionModification.CreateRemove(EnsureList <T>(args.OldItems))); #if !SILVERLIGHT case NotifyCollectionChangedAction.Move: return Observable.Empty <CollectionModification <T> >(); #endif case NotifyCollectionChangedAction.Replace: return Observable.Return(CollectionModification.CreateRemove(EnsureList <T>(args.OldItems))) .Concat(Observable.Return(CollectionModification.CreateAdd(EnsureList <T>(args.NewItems)))); case NotifyCollectionChangedAction.Reset: return Observable.Return(CollectionModification.CreateClear <T>()); default: throw new InvalidOperationException(); } })); }
public void OnNext(CollectionModification <KeyValuePair <TKey, TValue> > value) { }
/// <summary> /// Changes the dictionary according to the specified collection modification. This method is not supported. /// </summary> /// <param name="value">A modification that indicates how the dictionary must be changed.</param> /// <exception cref="NotSupportedException">Attempted to set an item in a read-only dictionary.</exception> public void OnNext(CollectionModification <KeyValuePair <TKey, TValue> > value) { throw new NotSupportedException(); }
/// <summary> /// Changes the list according to the specified collection modification. This method is not supported. /// </summary> /// <param name="value">A modification that indicates how the list must be changed.</param> /// <exception cref="NotSupportedException">Attempted to modify a read-only list.</exception> public void OnNext(CollectionModification <T> value) { throw new NotSupportedException(); }
public void OnNext(CollectionModification <T> value) { }
internal static ReadOnlyListSubject <TResult> CollectInternal <TResult>( this FileSystemWatcher watcher, bool composited, Func <IObservable <CollectionNotification <string> >, IObservable <CollectionModification <TResult> > > selector, IScheduler scheduler) { Contract.Requires(watcher != null); Contract.Requires(selector != null); Contract.Requires(scheduler != null); Contract.Ensures(Contract.Result <ReadOnlyListSubject <TResult> >() != null); var existing = Directory .EnumerateFiles( watcher.Path, watcher.Filter, watcher.IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); var changes = watcher .Watch(WatcherChangeTypes.Created | WatcherChangeTypes.Deleted | WatcherChangeTypes.Renamed) .SelectMany(notification => notification.Change == WatcherChangeTypes.Created ? Observable.Return(CollectionModification.CreateAdd(notification.FullPath)) : notification.Change == WatcherChangeTypes.Deleted ? Observable.Return(CollectionModification.CreateRemove(notification.FullPath)) : Observable.Return(CollectionModification.CreateRemove(notification.OldFullPath)).Concat(Observable.Return(CollectionModification.CreateAdd(notification.FullPath)))); if (composited) { changes = changes.Finally(watcher.Dispose); } return(existing.ToObservable(scheduler).Collect(changes.ObserveOn(scheduler), selector, StringComparer.OrdinalIgnoreCase)); }