My project is MVVM and I had been using ReactiveList<T> as my go-to observable collection for viewmodel properties. But ReactiveUI deprecated ReactiveList in 8.6.1. So I needed to get on to the new recommended library: DynamicData.
But there is no direct drop-in replacement you can do like ObservableCollection<T> <-> ReactiveList<T>. I grabbed the NuGet package, dropped in SourceList<T>, but that doesn’t work. SourceList<T> does not implement INotifyCollectionChanged, which is what WPF looks for when binding to ListView, GridView, ItemsControl, etc. So how do we bind to this thing? After some fruitless searches I dug through the source code unit tests and found the answer. Add this to the viewmodel class:
private readonly SourceList<string> myList = new SourceList<string>(); public IObservableCollection<string> MyListBindable { get; } = new ObservableCollectionExtended<string>();
And this to its constructor:
this.myList.Connect().Bind(this.MyListBindable).Subscribe();
It’s a two-stage affair. The SourceList<T> is where all the operations happen. Adds, clears, deletes and all that. But you don’t directly observe the source list. To do that, you need to call Connect() to get an IObservable<IChangeSet<T>> . If you follow this observable you can see everything that’s changed about the collection by looking at the change sets.
But you still need to do one more thing: get it in a format that the WPF UI can bind to, that is an object that implements INotifyCollectionChanged. ObservableCollectionExtended is DynamicData’s implementation of that. The Bind() call “slaves” it to the SourceList. Any changes made in the SourceList are now reflected in the ObservableCollectionExtended. A final call to Subscribe() activates it. Now since we’re exposing it as a property, we can bind our UI to it:
<ItemsControl ItemsSource="{Binding MyListBindable}" ...
The important thing here is to remember that this property is here ONLY so the UI can bind to it. That’s why I’ve named it Bindable: so I’ll realize I’m doing something wrong if I try to modify it directly.
The ObservableCollectionExtended property also allows you to get batches to avoid update churn from making individual edits to the collection. When you call Edit() on the SourceList<T>:
this.myList.Edit(innerList => { innerList.Clear(); foreach (string name in names) { innerList.Add(name); } });
It will batch up all the changes made into one event under INotifyCollectionChanged, meaning the UI only needs to react once.
OMG. You saved my day.
I was looking for a quick answer to this newbiew problem when I tried to update my code from ReactiveList to DynamicData.
Thanks a lot.
Thank you!!! This entry is so helpful!!