Search code examples
mvvmxamarin.formsdynamic-datareactiveui

ReactiveUI and DynamicData SourceCache update issue


I am using SouceCache from DynamicData in my Xamarin Forms project to track changes from the backend. First I am getting the list of Items from backend, populate the UI and then wait for changes.

The issue is that when new(updated) object arrives from backend, I find and update it in an _innerCache collection, there is no new value emitted from observable, and UI is not updated.

Code is simplified but it is something like this:

_internalSourceCache = new SourceCache<Item, string>(o => o.Id);

public IObservable<IChangeSet<Item, string>> Connect() => _internalSourceCache.Connect();

private void OnItemUpdated(List<Item> items)
        {
            foreach (var item in items)
            {
                _internalSourceCache.Edit(innerCache =>
                {
                    innerCache.AddOrUpdate(item);
                });
            }
        }

And in a view model where I need those changes:

itemsService
     .Connect()
     .Transform(item=>
           {

               return new ItemCellViewModel(item);
           }, (_, n) => _ = new ItemCellViewModel(n))
     .Sort(SortExpressionComparer<ItemCellViewModel>.Descending(t => t.Status))
     .DisposeMany()
     .ObserveOn(MainThreadScheduler)
     .Bind(out _items)
     .Subscribe();

I am obviously missing something, but I still don't know what, so please help if you see the problem :)


Solution

  • There is nothing obviously wrong and all these operators are commonly used. Could it be that an exception is being thrown? To test for this you can add a Do statement and debug or write to the console. For example:

        .Do(changes => Console.WriteLine(changes), ex => Console.WriteLine(ex))
        .Transform(item => new ItemCellViewModel(item))
        .Do(changes => Console.WriteLine(changes), ex => Console.WriteLine(ex))
    

    Doing this before and after each operator will allow you to narrow down the issue.

    Additionally but completely unrelated to your question, never update a source like this

        foreach (var item in items)
        {
            _internalSourceCache.Edit(innerCache =>
            {
                innerCache.AddOrUpdate(item);
            });
        }
    

    as it is super inefficient. In this case an new change set will be emitted for every item and will be transmitted along the chain. Instead you should either do this

        _internalSourceCache.Edit(innerCache =>
        {
            \\ doing it this way will only product a single changeset
            foreach (var item in items)
                innerCache.AddOrUpdate(item);
        });
    

    or if there is no logic to apply,

        _internalSourceCache.AddOrUpdate(items);