Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds optional useReplaceForUpdates to SortedObservableCollectionAdaptor #726

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
/// <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 @@

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);

Check warning on line 763 in src/DynamicData/Cache/ObservableCacheEx.cs

View check run for this annotation

Codecov / codecov/patch

src/DynamicData/Cache/ObservableCacheEx.cs#L763

Added line #L763 was not covered by tests
readOnlyObservableCollection = result;
return source.Bind(target, updater);
}
Expand Down