Skip to content

Commit b3180bc

Browse files
authored
Adds optional "useReplaceForUpdates" to SortedObservableCollectionAdaptor (#726)
1 parent 4e9a209 commit b3180bc

File tree

3 files changed

+41
-17
lines changed

3 files changed

+41
-17
lines changed

src/DynamicData.Tests/Binding/ObservableCollectionBindCacheSortedFixture.cs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,42 @@ public void UpdateToSourceSendsRemoveAndAddIfSortingIsAffected()
196196
[Fact]
197197
public void UpdateToSourceSendsReplaceIfSortingIsNotAffected()
198198
{
199-
var person1 = new Person("Adult1", 10);
200-
var person2 = new Person("Adult2", 11);
201-
202-
NotifyCollectionChangedAction action = default;
203-
_source.AddOrUpdate(person1);
204-
_source.AddOrUpdate(person2);
199+
RunTest(true);
200+
RunTest(false);
205201

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

208-
using (_collection.ObserveCollectionChanges().Select(change => change.EventArgs.Action).Subscribe(act => action = act))
203+
void RunTest(bool useReplace)
209204
{
210-
_source.AddOrUpdate(person2Updated);
211-
}
205+
var collection = new ObservableCollectionExtended<Person>();
206+
207+
using var source = new SourceCache<Person, string>(p => p.Name);
208+
using var binder = source.Connect().Sort(_comparer, resetThreshold: 25).Bind(collection, new ObservableCollectionAdaptor<Person, string>(useReplaceForUpdates: useReplace)).Subscribe();
209+
210+
var person1 = new Person("Adult1", 10);
211+
var person2 = new Person("Adult2", 11);
212+
213+
NotifyCollectionChangedAction action = default;
214+
source.AddOrUpdate(person1);
215+
source.AddOrUpdate(person2);
216+
217+
var person2Updated = new Person("Adult2", 12);
212218

213-
action.Should().Be(NotifyCollectionChangedAction.Replace, "The notification type should be Replace");
214-
_collection.Should().Equal(person1, person2Updated);
219+
using (collection.ObserveCollectionChanges().Select(x => x.EventArgs.Action).Subscribe(updateType => action = updateType))
220+
{
221+
source.AddOrUpdate(person2Updated);
222+
}
223+
224+
if (useReplace)
225+
{
226+
action.Should().Be(NotifyCollectionChangedAction.Replace, "The notification type should be Replace");
227+
}
228+
else
229+
{
230+
action.Should().Be(NotifyCollectionChangedAction.Add, "The notification type should be Add");
231+
}
232+
233+
collection.Should().Equal(person1, person2Updated);
234+
}
215235
}
216236

217237
[Fact]

src/DynamicData/Binding/SortedObservableCollectionAdaptor.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ public class SortedObservableCollectionAdaptor<TObject, TKey> : ISortedObservabl
1818
where TKey : notnull
1919
{
2020
private readonly int _refreshThreshold;
21+
private readonly bool _useReplaceForUpdates;
2122

2223
/// <summary>
2324
/// Initializes a new instance of the <see cref="SortedObservableCollectionAdaptor{TObject, TKey}"/> class.
2425
/// </summary>
2526
/// <param name="refreshThreshold">The number of changes before a Reset event is used.</param>
26-
public SortedObservableCollectionAdaptor(int refreshThreshold = 25)
27+
/// <param name="useReplaceForUpdates"> Use replace instead of remove / add for updates. </param>
28+
public SortedObservableCollectionAdaptor(int refreshThreshold = 25, bool useReplaceForUpdates = true)
2729
{
2830
_refreshThreshold = refreshThreshold;
31+
_useReplaceForUpdates = useReplaceForUpdates;
2932
}
3033

3134
/// <summary>
@@ -89,7 +92,7 @@ public void Adapt(ISortedChangeSet<TObject, TKey> changes, IObservableCollection
8992
}
9093
}
9194

92-
private static void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservableCollection<TObject> list)
95+
private void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservableCollection<TObject> list)
9396
{
9497
foreach (var update in updates)
9598
{
@@ -108,7 +111,7 @@ private static void DoUpdate(ISortedChangeSet<TObject, TKey> updates, IObservabl
108111
break;
109112

110113
case ChangeReason.Update:
111-
if (update.PreviousIndex != update.CurrentIndex)
114+
if (!_useReplaceForUpdates || update.PreviousIndex != update.CurrentIndex)
112115
{
113116
list.RemoveAt(update.PreviousIndex);
114117
list.Insert(update.CurrentIndex, update.Current);

src/DynamicData/Cache/ObservableCacheEx.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,10 +745,11 @@ public static IObservable<ISortedChangeSet<TObject, TKey>> Bind<TObject, TKey>(t
745745
/// <param name="source">The source.</param>
746746
/// <param name="readOnlyObservableCollection">The resulting read only observable collection.</param>
747747
/// <param name="resetThreshold">The number of changes before a reset event is called on the observable collection.</param>
748+
/// <param name="useReplaceForUpdates"> Use replace instead of remove / add for updates. NB: Some platforms to not support replace notifications for binding.</param>
748749
/// <param name="adaptor">Specify an adaptor to change the algorithm to update the target collection.</param>
749750
/// <returns>An observable which will emit change sets.</returns>
750751
/// <exception cref="System.ArgumentNullException">source.</exception>
751-
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)
752+
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)
752753
where TObject : notnull
753754
where TKey : notnull
754755
{
@@ -759,7 +760,7 @@ public static IObservable<IChangeSet<TObject, TKey>> Bind<TObject, TKey>(this IO
759760

760761
var target = new ObservableCollectionExtended<TObject>();
761762
var result = new ReadOnlyObservableCollection<TObject>(target);
762-
var updater = adaptor ?? new SortedObservableCollectionAdaptor<TObject, TKey>(resetThreshold);
763+
var updater = adaptor ?? new SortedObservableCollectionAdaptor<TObject, TKey>(resetThreshold, useReplaceForUpdates);
763764
readOnlyObservableCollection = result;
764765
return source.Bind(target, updater);
765766
}

0 commit comments

Comments
 (0)