Entry No. 17

Convert Reactive List To Dynamic Data.

What is ReactiveList

A built-in class come along with ReactiveUI to replace ObservableCollection. It is similar to a list but has the power of Rx.

But it is clumsy, buggy and becoming unstable. People who using it may encounter many bugs, app crashing and it’s quite not a thread-safe.

What is Dynamic Data

DynamicData is reactive collections based on Rx.Net, provide an API which allows the consumers to observe changes and act on those changes. The changes are accessible via .Connect(). The idea is to create the data source first and bind it later.

Creating
var myList = new SourceList<T>()

// Or likes this
var myList = new SourceCache<TObject,TKey>(t => key);

var myConnection = myList.Connect()

We can do anything with myList in the background thread and then Connect and Bind it to UI. 
This is safe and consumes less of our valuable Main Thread Time.

Question:
  • SourceList vs SourceCache, which one is better?
Answer:
  • SourceCache has every advantage over SourceList. It can notifies when update which SourceList has no idea how.
  • But the cache requires the no duplicate collection and unique ID. If we not sure our list will have duplicate items or when it’s quite hard to maintain the ID, just use SourceList.

Side Effects

Many people have used this and approved, it’s very stable.

Consider both of them on every aspect, we can easily decide to replace ReactiveList with DynamicData. A common mistake a lot of users make is trying to expose DynamicData classes to the world, eg: pass the sourceList as the parameter.

How to convert ReactiveList to Dynamic Data

We can follow the following pattern:

// for mutation
private readonly SourceList<T> _itemsSourceList = new SourceList<T>();

// for observing
private readonly IObservableList<T> _itemsObservableList = new IObservableList<T>();
IObservableList<T> Interface.ItemsObservableList => _itemsObservableList;

// for binding to UI
private readonly ReadOnlyObservableCollection<T> _itemsBinding;
ReadOnlyObservableCollection<T> Interface.ItemsBinding => _itemsBinding;

Constructor
{
    _itemsSourceList
            .Connect() // make the source an observable change set
            .ObserveOn(RxApp.MainThreadScheduler) // Ensure the updates arrive on the UI thread
            .Bind(out _itemsBinding)
            .Subscribe();
    
    _itemsObservableList = _itemsSourceList.AsObservableList();
}

DoThing()
{
    // batch edit
    _itemsSourceList.Edit(innerList =>
    {
        innerList.Clear();
        innerList.AddRange(inputList);
    });
}

Binding()
{
    // observe the changing
    this.WhenAnyObservable(vm => vm._itemsSourceList.CountChanged)
        .Subscribe(_ =>
        {
            // do something
        });
}
Notes:
  • The binding property ReadOnlyObservableCollection from sourceList can only be used for binding.
  • We use IObservableList property to pass around.