Skip to content

Commit

Permalink
Adds optional "useReplaceForUpdates" to SortedObservableCollectionAda…
Browse files Browse the repository at this point in the history
…ptor (#726)
  • Loading branch information
ccopsey authored Sep 22, 2023
1 parent 4e9a209 commit b3180bc
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -196,22 +196,42 @@ public void UpdateToSourceSendsRemoveAndAddIfSortingIsAffected()
[Fact]
public void UpdateToSourceSendsReplaceIfSortingIsNotAffected()
{
var person1 = new Person("Adult1", 10);
var person2 = new Person("Adult2", 11);

NotifyCollectionChangedAction action = default;
_source.AddOrUpdate(person1);
_source.AddOrUpdate(person2);
RunTest(true);
RunTest(false);

var person2Updated = new Person("Adult2", 12);

using (_collection.ObserveCollectionChanges().Select(change => change.EventArgs.Action).Subscribe(act => action = act))
void RunTest(bool useReplace)
{
_source.AddOrUpdate(person2Updated);
}
var collection = new ObservableCollectionExtended<Person>();

using var source = new SourceCache<Person, string>(p => p.Name);
using var binder = source.Connect().Sort(_comparer, resetThreshold: 25).Bind(collection, new ObservableCollectionAdaptor<Person, string>(useReplaceForUpdates: useReplace)).Subscribe();

var person1 = new Person("Adult1", 10);
var person2 = new Person("Adult2", 11);

NotifyCollectionChangedAction action = default;
source.AddOrUpdate(person1);
source.AddOrUpdate(person2);

var person2Updated = new Person("Adult2", 12);

action.Should().Be(NotifyCollectionChangedAction.Replace, "The notification type should be Replace");
_collection.Should().Equal(person1, person2Updated);
using (collection.ObserveCollectionChanges().Select(x => x.EventArgs.Action).Subscribe(updateType => action = updateType))
{
source.AddOrUpdate(person2Updated);
}

if (useReplace)
{
action.Should().Be(NotifyCollectionChangedAction.Replace, "The notification type should be Replace");
}
else
{
action.Should().Be(NotifyCollectionChangedAction.Add, "The notification type should be Add");
}

collection.Should().Equal(person1, person2Updated);
}
}

[Fact]
Expand Down
9 changes: 6 additions & 3 deletions src/DynamicData/Binding/SortedObservableCollectionAdaptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ public class SortedObservableCollectionAdaptor<TObject, TKey> : ISortedObservabl
where TKey : notnull
{
private readonly int _refreshThreshold;
private readonly bool _useReplaceForUpdates;

/// <summary>
/// Initializes a new instance of the <see cref="SortedObservableCollectionAdaptor{TObject, TKey}"/> class.
/// </summary>
/// <param name="refreshThreshold">The number of changes before a Reset event is used.</param>
public SortedObservableCollectionAdaptor(int refreshThreshold = 25)
/// <param name="useReplaceForUpdates"> Use replace instead of remove / add for updates. </param>
public SortedObservableCollectionAdaptor(int refreshThreshold = 25, bool useReplaceForUpdates = true)
{
_refreshThreshold = refreshThreshold;
_useReplaceForUpdates = useReplaceForUpdates;
}

/// <summary>
Expand Down Expand Up @@ -89,7 +92,7 @@ public void Adapt(ISortedChangeSet<TObject, TKey> changes, IObservableCollection
}
}

private static void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservableCollection<TObject> list)
private void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservableCollection<TObject> list)
{
foreach (var update in updates)
{
Expand All @@ -108,7 +111,7 @@ private static void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservabl
break;

case ChangeReason.Update:
if (update.PreviousIndex != update.CurrentIndex)
if (!_useReplaceForUpdates || update.PreviousIndex != update.CurrentIndex)
{
list.RemoveAt(update.PreviousIndex);
list.Insert(update.CurrentIndex, update.Current);
Expand Down
5 changes: 3 additions & 2 deletions src/DynamicData/Cache/ObservableCacheEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -745,10 +745,11 @@ public static IObservable<ISortedChangeSet<TObject, TKey>> Bind<TObject, TKey>(t
/// <param name="source">The source.</param>
/// <param name="readOnlyObservableCollection">The resulting read only observable collection.</param>
/// <param name="resetThreshold">The number of changes before a reset event is called on the observable collection.</param>
/// <param name="useReplaceForUpdates"> Use replace instead of remove / add for updates. NB: Some platforms to not support replace notifications for binding.</param>
/// <param name="adaptor">Specify an adaptor to change the algorithm to update the target collection.</param>
/// <returns>An observable which will emit change sets.</returns>
/// <exception cref="System.ArgumentNullException">source.</exception>
public static IObservable<IChangeSet<TObject, TKey>> Bind<TObject, TKey>(this IObservable<ISortedChangeSet<TObject, TKey>> source, out ReadOnlyObservableCollection<TObject> readOnlyObservableCollection, int resetThreshold = 25, ISortedObservableCollectionAdaptor<TObject, TKey>? adaptor = null)
public static IObservable<IChangeSet<TObject, TKey>> Bind<TObject, TKey>(this IObservable<ISortedChangeSet<TObject, TKey>> source, out ReadOnlyObservableCollection<TObject> readOnlyObservableCollection, int resetThreshold = 25, bool useReplaceForUpdates = true, ISortedObservableCollectionAdaptor<TObject, TKey>? adaptor = null)
where TObject : notnull
where TKey : notnull
{
Expand All @@ -759,7 +760,7 @@ public static IObservable<IChangeSet<TObject, TKey>> Bind<TObject, TKey>(this IO

var target = new ObservableCollectionExtended<TObject>();
var result = new ReadOnlyObservableCollection<TObject>(target);
var updater = adaptor ?? new SortedObservableCollectionAdaptor<TObject, TKey>(resetThreshold);
var updater = adaptor ?? new SortedObservableCollectionAdaptor<TObject, TKey>(resetThreshold, useReplaceForUpdates);
readOnlyObservableCollection = result;
return source.Bind(target, updater);
}
Expand Down

0 comments on commit b3180bc

Please sign in to comment.