3

I am making multiple updates to a SourceCache using the Edit method. But when observing the changes for the resulting collection, the updates are returned one at a time. Furthermore, when the update threshold limit of 25 is reached, then the entire list is cleared and updated. While the items in the collection are valid, the UI animations based on the changes are not ideal. Especially in the case where the entire collection is cleared and rebuilt. Following snippet reproduces the issue:

Sample Snippet:

    public class DynamicDataTest
    {
        private readonly SourceCache<string, string> _sourceCache = new SourceCache<string, string>(x => x);
        private readonly ReadOnlyObservableCollection<string> _collection;

        public DynamicDataTest()
        {
            _sourceCache.Connect()
                //.Sort(SortExpressionComparer<string>.Ascending(l => l))
                .Bind(out _collection)
                .Subscribe();

            new SourceList<string>(_collection.ToObservableChangeSet())
                .Connect()
                .ForEachChange(change => Console.WriteLine(change.Reason.ToString()))
                .Subscribe();

            _sourceCache.AddOrUpdate("start");
            _sourceCache.Edit(source =>
            {
                for (int i = 0; i < 26; i++)
                {
                    source.AddOrUpdate(i.ToString());
                }
            });
        }
    }

I would expect this to output:

Add or AddRange
AddRange

Instead it results in:

AddRange
Clear
AddRange
Alex
  • 2,033
  • 1
  • 24
  • 40

1 Answers1

4

This is the intended behaviour.

When binding to an observable collection, there is a balance to be made. When you have a lot of changes to apply, sending a reset notification is normally faster than applying the changes one at the time. The reset suspends the notify collection change event then clears and reloads the list. After which it fires a reset. This is why you are seeing the additional Clear / Add range

This is controlled by the reset threshold option in the bind operator. For example

.Bind(out _collection, resetThreshold:100) //default=25

will fire a reset when there are 100 changes to apply, whereas

 .Bind(out _collection, resetThreshold:int.MaxValue)

will ensure reset is never used.

Roland Pheasant
  • 1,161
  • 8
  • 8
  • That makes sense but why are the changes in Edit() not batched together? If the _souceCache is empty, adding 20 items to the list with an Edit creates a single change event. But if one item already exists, then 20 separate changes are created. Is it an optimization that is missing? – Alex Oct 02 '20 at 17:40
  • 2
    Changes made inside edit are batched together to produce a single change set notification. The reason for seeing multiple individual updates is due to creating a change set from the observable collection. The observable collection is producing individual changes as it handles updating one element at a time. This comes from some platforms not being able to handle batch amendments of the observable collection – Roland Pheasant Oct 04 '20 at 17:19