/// <summary> /// Suspends the change notifications until the returned <see cref="IDisposable"/> is disposed. /// <example> /// <code> /// <![CDATA[ /// var fastCollection = new FastObservableCollection<int>(); /// using (fastCollection.SuspendChangeNotificaftions()) /// { /// // Adding or removing events inside here will not raise events /// fastCollection.Add(1); /// fastCollection.Add(2); /// fastCollection.Add(3); /// /// fastCollection.Remove(3); /// fastCollection.Remove(2); /// fastCollection.Remove(1); /// } /// ]]> /// </code> /// </example> /// </summary> /// <param name="mode">The suspension Mode.</param> /// <returns>IDisposable.</returns> public IDisposable SuspendChangeNotifications(SuspensionMode mode) { if (_suspensionContext == null) { // Create new context _suspensionContext = new SuspensionContext <T>(mode); } else if (_suspensionContext != null && _suspensionContext.Mode != mode) { throw Log.ErrorAndCreateException <InvalidOperationException>("Cannot change mode during another active suspension."); } return(new DisposableToken <FastObservableCollection <T> >( this, x => { x.Instance._suspensionContext.Count++; }, x => { x.Instance._suspensionContext.Count--; if (x.Instance._suspensionContext.Count == 0) { if (x.Instance.IsDirty) { x.Instance.IsDirty = false; x.Instance.NotifyChanges(); } x.Instance._suspensionContext = null; } }, _suspensionContext)); }
/// <summary> /// Removes the specified items from the collection without causing a change notification for all items. /// <para /> /// This method will raise a change notification at the end. /// </summary> /// <param name="collection">The collection.</param> /// <param name="mode">The suspension mode.</param> /// <exception cref="ArgumentNullException">The <paramref name="collection"/> is <c>null</c>.</exception> public void RemoveItems(IEnumerable <T> collection, SuspensionMode mode) { Argument.IsNotNull("collection", collection); using (SuspendChangeNotifications(mode)) { foreach (var item in collection) { Remove(item); } } }
/// <summary> /// Transforms the <see cref="SuspensionMode"/> into its equivalent <see cref="NotifyCollectionChangedAction"/>. /// </summary> /// <param name="mode">The suspension mode.</param> /// <returns>The equivalent <see cref="NotifyCollectionChangedAction"/>.</returns> private static NotifyCollectionChangedAction ModeToAction(SuspensionMode mode) { // Only transform modes Adding and Removing, others fail switch (mode) { case SuspensionMode.Adding: return(NotifyCollectionChangedAction.Add); case SuspensionMode.Removing: return(NotifyCollectionChangedAction.Remove); default: throw new ArgumentException($"Wrong mode '{mode}' for constructor."); } }
/// <summary> /// Inserts the elements of the specified collection at the specified index. /// <para /> /// This method will raise a change notification at the end. /// </summary> /// <param name="collection">The collection.</param> /// <param name="index">The start index.</param> /// <param name="mode">The suspension mode.</param> /// <exception cref="ArgumentNullException">The <paramref name="collection"/> is <c>null</c>.</exception> public virtual void InsertItems(IEnumerable <T> collection, int index, SuspensionMode mode) { Argument.IsNotNull("collection", collection); using (SuspendChangeNotifications(mode)) { foreach (var item in collection) { Insert(index++, item); } } }
/// <summary> /// Initializes a new instance of the <see cref="NotifyRangedCollectionChangedEventArgs"/> class. /// </summary> /// <param name="changedItems">The changed items.</param> /// <param name="indices">The indices.</param> /// <param name="mode">The suspension mode.</param> /// <param name="action">The action.</param> /// <remarks>This is only for use of <see cref="Catel.Collections.SuspensionMode.MixedBash"/>.</remarks> public NotifyRangedCollectionChangedEventArgs(IList changedItems, IList <int> indices, SuspensionMode mode, NotifyCollectionChangedAction action) : base(EnsureModeAndAction(mode, action), changedItems, (indices != null && indices.Count != 0) ? indices[0] : -1) { Argument.IsNotNull(nameof(changedItems), changedItems); Argument.IsNotNull(nameof(indices), indices); // ReSharper disable once PossibleNullReferenceException Argument.IsNotOutOfRange(nameof(indices), indices.Count, changedItems.Count, changedItems.Count); ChangedItems = changedItems; Indices = indices; SuspensionMode = mode; }
/// <summary> /// Adds the specified items to the collection without causing a change notification for all items. /// <para /> /// This method will raise a change notification at the end. /// </summary> /// <param name="collection">The collection.</param> /// <param name="mode">The suspension mode.</param> /// <exception cref="ArgumentNullException">The <paramref name="collection"/> is <c>null</c>.</exception> public void AddItems(IEnumerable collection, SuspensionMode mode) { Argument.IsNotNull("collection", collection); using (SuspendChangeNotifications(mode)) { foreach (var item in collection) { ((IList)this).Add(item); } } }
/// <summary> /// The ensure mode and action. /// </summary> /// <param name="mode">The suspension mode.</param> /// <param name="action">The action.</param> /// <returns>The <see cref="NotifyCollectionChangedAction"/>.</returns> private static NotifyCollectionChangedAction EnsureModeAndAction(SuspensionMode mode, NotifyCollectionChangedAction action) { // Check for mixed modes except for Mixed, others fail if (mode == SuspensionMode.Mixed || !mode.IsMixedMode()) { throw new ArgumentException($"Wrong mode '{mode}' for constructor."); } // Check for action Add or Remove, others fail switch (action) { case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: return(action); default: throw new ArgumentException($"Wrong action '{action}' for constructor."); } }
/// <summary> /// Suspends the change notifications until the returned <see cref="IDisposable"/> is disposed. /// <example> /// <code> /// <![CDATA[ /// var fastCollection = new FastBindingList<int>(); /// using (fastCollection.SuspendChangeNotificaftions()) /// { /// // Adding or removing events inside here will not raise events /// fastCollection.Add(1); /// fastCollection.Add(2); /// fastCollection.Add(3); /// /// fastCollection.Remove(3); /// fastCollection.Remove(2); /// fastCollection.Remove(1); /// } /// ]]> /// </code> /// </example> /// </summary> /// <param name="mode">The suspension Mode.</param> /// <returns>IDisposable.</returns> public IDisposable SuspendChangeNotifications(SuspensionMode mode) { if (_suspensionContext is null) { // Create new context _suspensionContext = new ExtendedSuspensionContext <T>(mode); } else if (_suspensionContext.Mode != mode) { throw Log.ErrorAndCreateException <InvalidOperationException>("Cannot change mode during another active suspension."); } return(new DisposableToken <FastBindingList <T> >( this, x => { if (x.Instance._suspensionContext.Count == 0) { x.Instance.RaiseListChangedEvents = false; x.Instance.IsDirty = true; } x.Instance._suspensionContext.Count++; }, x => { x.Instance._suspensionContext.Count--; if (x.Instance._suspensionContext.Count == 0) { x.Instance.RaiseListChangedEvents = true; x.Instance.IsDirty = false; x.Instance.NotifyChanges(); x.Instance._suspensionContext = null; } }, _suspensionContext)); }
/// <summary> /// The is mixed mode. /// </summary> /// <param name="suspensionMode">The suspension Mode.</param> /// <returns><c>True</c> if <see cref="SuspensionMode"/> is one of the mixed modes; otherwise, <c>false</c>.</returns> public static bool IsMixedMode(this SuspensionMode suspensionMode) { return(MixedModes.Contains(suspensionMode)); }
/// <summary> /// Initializes a new instance of the <see cref="ExtendedSuspensionContext{T}" /> class. /// </summary> /// <param name="mode">The suspension mode.</param> public ExtendedSuspensionContext(SuspensionMode mode) { _suspensionMode = mode; }
/// <summary> /// Initializes a new instance of the <see cref="SuspensionContext{T}" /> class. /// </summary> /// <param name="mode">The suspension mode.</param> public SuspensionContext(SuspensionMode mode) { _suspensionMode = mode; }
/// <summary> /// Creates the bash event args list. /// </summary> /// <param name="suspensionContext">The suspension context.</param> /// <param name="suspensionMode">The suspension mode.</param> /// <typeparam name="T">The type of collection item.</typeparam> /// <returns>The <see cref="IList{NotifyRangedCollectionChangedEventArgs}"/>.</returns> private static IList <NotifyRangedCollectionChangedEventArgs> CreateBashEvents <T>(this SuspensionContext <T> suspensionContext, SuspensionMode suspensionMode) { var i = 0; var changedItems = new List <T>(); var changedItemIndices = new List <int>(); var previousAction = (NotifyCollectionChangedAction?)null; var eventArgsList = new List <NotifyRangedCollectionChangedEventArgs>(); foreach (var action in suspensionContext.MixedActions) { // If action changed, create event args for remembered items if (previousAction.HasValue && action != previousAction.Value) { // Create and add event args eventArgsList.Add(new NotifyRangedCollectionChangedEventArgs(changedItems, changedItemIndices, suspensionMode, previousAction.Value)); // Reset lists changedItems = new List <T>(); changedItemIndices = new List <int>(); } // Remember item and index changedItems.Add(suspensionContext.ChangedItems[i]); changedItemIndices.Add(suspensionContext.ChangedItemIndices[i]); // Update to current action previousAction = action; i++; } // Create event args for last item(s) if (changedItems.Count != 0 && previousAction != null) { eventArgsList.Add(new NotifyRangedCollectionChangedEventArgs(changedItems, changedItemIndices, suspensionMode, previousAction.Value)); } return(eventArgsList); }
public new IDisposable SuspendChangeNotifications(SuspensionMode mode) { _initialCount = Count; return(base.SuspendChangeNotifications(mode)); }