0

Consider having two SourceCaches with a different key:

var sourceCacheA = new SourceCache<MyType, int>(x => x.Prop1);
var sourceCacheB = new SourceCache<MyType, string>(x => x.Prop2);

where are both connected:

var observableA = sourceCacheA.Connect();
var observableB = sourceCacheB.Connect();

Let's say the observableA is bound to a ReadOnlyObservableCollection as follows:

observableA.ObserveOn(RxApp.MainThreadScheduler).Bind(out _targetCollection).Subscribe();

How to build an observable that can be changed during runtime, while bound to the same _targetCollection.

So basically, it shall operate like this:

if(somethingHappenBool)
{
    **observableA**.ObserveOn(RxApp.MainThreadScheduler).Bind(out _targetCollection).Subscribe();
} 
else
{
    **observableB**.ObserveOn(RxApp.MainThreadScheduler).Bind(out _targetCollection).Subscribe();
}

EDIT:

Based on Jason's answer I came up with the following solution:

public enum SwitchDataSourceOption
{
    SourceA,
    SourceB
}
public SwitchDataSourceOption Option
{
    get => _option;
    set
    {
        _option = value;
        NotifyPropertyChanged(nameof(Option));
    }
}

sourceCacheA = new SourceCache<MyType, int>(x => x.AProp);
sourceCacheB = new SourceCache<MyType, int>(x => x.BProp);

this.WhenAnyValue(x => x.Option)
    .Select(opt => opt == SwitchDataSourceOption.SourceA ? sourceCacheA : sourceCacheB)
    .Switch()
    .AsObservableCache()
    .Connect()
    .ObserveOn(RxApp.MainThreadScheduler)
    .Bind(out _targetCollection)
    .Subscribe();

However, I don't know how to handle various key types, as in my original example I have int and string as key

Pythoneer
  • 87
  • 6

1 Answers1

0

It looks like you can make the collection yourself:

var collection = new ObservableCollectionExtended<MyType>();

And bind to it with

observableA.Bind(collection);

So you don't have to create a new collection with the bind.


Generally when I want to change observables at runtime, I think of the event that would change the observable as an observable itself.

I am not too familiar with ReactiveUI, but I suspect the behavior you want could be solved with the following code:

var sourceCacheA = new SourceCache<MyType, int>(x => x.Prop1);
var sourceCacheB = new SourceCache<MyType, string>(x => x.Prop2);

var observableA = sourceCacheA.Connect();
var observableB = sourceCacheB.Connect();

// Some change stream
var somethingHappened = new Subject<bool>(); 

// Create observable collection manually
var collection = new ObservableCollectionExtended<MyType>();

// Project to Unit so that types are the same
var bindToA = observableA.Bind(collection).Select(_ => Unit.Default);
var bindToB = observableB.Bind(collection).Select(_ => Unit.Default);

// Create observable that unsubscribes from the current and subscribes to the other when something happens
var mergedObservable = somethingHappened
    .StartWith(false)
    .Select(s => s ? bindToA : bindToB)
    .Switch();

// Begin monitoring changes
mergedObservable.Subscribe();

somethingHappened.OnNext(true);

sourceCacheA.Edit(i => i.AddOrUpdate(new [] {new MyType { Prop1 = 1}, new MyType { Prop1 = 2}}));
// Collection contains 2 elements

sourceCacheA.Edit(i => i.Clear()); 
// Collection contains 0 elements

somethingHappened.OnNext(false);
sourceCacheB.Edit(i => i.AddOrUpdate(new [] {new MyType { Prop1 = 0, Prop2 = "1"}, new MyType { Prop1 = 0, Prop2 = "2"}}));
// Collection contains 2 elements

// This is ignored as the observer is currently only listening to sourceCacheB
sourceCacheA.Edit(i => i.AddOrUpdate(new [] {new MyType { Prop1 = 1}, new MyType { Prop1 = 2}}));
// Collection contains previous 2 elements

Note: Be aware that switch can potentially miss events between unsubscribing and subscribing to the new observable.

Jason
  • 1,505
  • 5
  • 9
  • Thanks! It works. However, I don't like the fact, that the ObservableCollection is mixing the two SourceCaches together. Checkout my latest edit, that is based on your answer. In my edit I don't know how to handle different types though. I'll mark your post as an answer. – Pythoneer Aug 08 '20 at 16:44
  • Yes, that is correct. I was looking for a base class of the change object, but didn't find a way to combine the keyed observables without using bind and projecting to Unit. Do note that these are merged observables, but only one source can ever emit a value that can be observed. – Jason Aug 08 '20 at 16:48
  • So basically, I need a mixture of your solution and mine solution that is derived from yours :) – Pythoneer Aug 08 '20 at 18:53