|
|
@@ -2,6 +2,7 @@
|
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
|
|
using System;
|
|
|
+using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.Specialized;
|
|
|
using System.ComponentModel;
|
|
|
@@ -59,7 +60,8 @@ namespace Avalonia.Collections
|
|
|
/// the index in the collection and the item.
|
|
|
/// </param>
|
|
|
/// <param name="reset">
|
|
|
- /// An action called when the collection is reset.
|
|
|
+ /// An action called when the collection is reset. This will be followed by calls to
|
|
|
+ /// <paramref name="added"/> for each item present in the collection after the reset.
|
|
|
/// </param>
|
|
|
/// <returns>A disposable used to terminate the subscription.</returns>
|
|
|
public static IDisposable ForEachItem<T>(
|
|
|
@@ -68,112 +70,38 @@ namespace Avalonia.Collections
|
|
|
Action<int, T> removed,
|
|
|
Action reset)
|
|
|
{
|
|
|
- int index;
|
|
|
-
|
|
|
- NotifyCollectionChangedEventHandler handler = (_, e) =>
|
|
|
+ void Add(int index, IList items)
|
|
|
{
|
|
|
- switch (e.Action)
|
|
|
+ foreach (T item in items)
|
|
|
{
|
|
|
- case NotifyCollectionChangedAction.Add:
|
|
|
- index = e.NewStartingIndex;
|
|
|
-
|
|
|
- foreach (T item in e.NewItems)
|
|
|
- {
|
|
|
- added(index++, item);
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case NotifyCollectionChangedAction.Replace:
|
|
|
- index = e.OldStartingIndex;
|
|
|
-
|
|
|
- foreach (T item in e.OldItems)
|
|
|
- {
|
|
|
- removed(index++, item);
|
|
|
- }
|
|
|
-
|
|
|
- index = e.NewStartingIndex;
|
|
|
-
|
|
|
- foreach (T item in e.NewItems)
|
|
|
- {
|
|
|
- added(index++, item);
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case NotifyCollectionChangedAction.Remove:
|
|
|
- index = e.OldStartingIndex;
|
|
|
-
|
|
|
- foreach (T item in e.OldItems)
|
|
|
- {
|
|
|
- removed(index++, item);
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case NotifyCollectionChangedAction.Reset:
|
|
|
- if (reset == null)
|
|
|
- {
|
|
|
- throw new InvalidOperationException(
|
|
|
- "Reset called on collection without reset handler.");
|
|
|
- }
|
|
|
-
|
|
|
- reset();
|
|
|
- break;
|
|
|
+ added(index++, item);
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
- index = 0;
|
|
|
- foreach (T i in collection)
|
|
|
+ void Remove(int index, IList items)
|
|
|
{
|
|
|
- added(index++, i);
|
|
|
+ for (var i = items.Count - 1; i >= 0; --i)
|
|
|
+ {
|
|
|
+ removed(index + i, (T)items[i]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- collection.CollectionChanged += handler;
|
|
|
-
|
|
|
- return Disposable.Create(() => collection.CollectionChanged -= handler);
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Invokes an action for each item in a collection and subsequently each item added or
|
|
|
- /// removed from the collection.
|
|
|
- /// </summary>
|
|
|
- /// <typeparam name="T">The type of the collection items.</typeparam>
|
|
|
- /// <param name="collection">The collection.</param>
|
|
|
- /// <param name="added">
|
|
|
- /// An action called initially with all items in the collection and subsequently with a
|
|
|
- /// list of items added to the collection. The parameters passed are the index of the
|
|
|
- /// first item added to the collection and the items added.
|
|
|
- /// </param>
|
|
|
- /// <param name="removed">
|
|
|
- /// An action called with all items removed from the collection. The parameters passed
|
|
|
- /// are the index of the first item removed from the collection and the items removed.
|
|
|
- /// </param>
|
|
|
- /// <param name="reset">
|
|
|
- /// An action called when the collection is reset.
|
|
|
- /// </param>
|
|
|
- /// <returns>A disposable used to terminate the subscription.</returns>
|
|
|
- public static IDisposable ForEachItem<T>(
|
|
|
- this IAvaloniaReadOnlyList<T> collection,
|
|
|
- Action<int, IEnumerable<T>> added,
|
|
|
- Action<int, IEnumerable<T>> removed,
|
|
|
- Action reset)
|
|
|
- {
|
|
|
NotifyCollectionChangedEventHandler handler = (_, e) =>
|
|
|
{
|
|
|
switch (e.Action)
|
|
|
{
|
|
|
case NotifyCollectionChangedAction.Add:
|
|
|
- added(e.NewStartingIndex, e.NewItems.Cast<T>());
|
|
|
+ Add(e.NewStartingIndex, e.NewItems);
|
|
|
break;
|
|
|
|
|
|
+ case NotifyCollectionChangedAction.Move:
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
|
- removed(e.OldStartingIndex, e.OldItems.Cast<T>());
|
|
|
- added(e.NewStartingIndex, e.NewItems.Cast<T>());
|
|
|
+ Remove(e.OldStartingIndex, e.OldItems);
|
|
|
+ Add(e.NewStartingIndex, e.NewItems);
|
|
|
break;
|
|
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
|
- removed(e.OldStartingIndex, e.OldItems.Cast<T>());
|
|
|
+ Remove(e.OldStartingIndex, e.OldItems);
|
|
|
break;
|
|
|
|
|
|
case NotifyCollectionChangedAction.Reset:
|
|
|
@@ -184,16 +112,31 @@ namespace Avalonia.Collections
|
|
|
}
|
|
|
|
|
|
reset();
|
|
|
+ Add(0, (IList)collection);
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- added(0, collection);
|
|
|
+ Add(0, (IList)collection);
|
|
|
collection.CollectionChanged += handler;
|
|
|
|
|
|
return Disposable.Create(() => collection.CollectionChanged -= handler);
|
|
|
}
|
|
|
|
|
|
+ public static IAvaloniaReadOnlyList<TDerived> CreateDerivedList<TSource, TDerived>(
|
|
|
+ this IAvaloniaReadOnlyList<TSource> collection,
|
|
|
+ Func<TSource, TDerived> select)
|
|
|
+ {
|
|
|
+ var result = new AvaloniaList<TDerived>();
|
|
|
+
|
|
|
+ collection.ForEachItem(
|
|
|
+ (i, item) => result.Insert(i, select(item)),
|
|
|
+ (i, item) => result.RemoveAt(i),
|
|
|
+ () => result.Clear());
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Listens for property changed events from all items in a collection.
|
|
|
/// </summary>
|