如何在运行时在 C# 中更改可观察对象?

How to change observables at runtime in C#?

考虑让两个 SourceCaches 使用不同的密钥:

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();

假设 observableA 绑定到 ReadOnlyObservableCollection,如下所示:

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

如何构建可在运行时更改的可观察对象,同时绑定到相同的 _targetCollection

所以基本上,它应该像这样运行:

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

编辑:

根据 Jason 的回答,我想出了以下解决方案:

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();

但是,我不知道如何处理各种键类型,因为在我原来的示例中我有 intstring 作为键

看来你可以自己制作合集了:

var collection = new ObservableCollectionExtended<MyType>();

并用

绑定到它
observableA.Bind(collection);

因此您不必使用绑定创建新集合。


一般来说,当我想在运行时更改可观察对象时,我会将更改可观察对象的事件视为可观察对象本身。

我对 ReactiveUI 不太熟悉,但我怀疑您想要的行为可以通过以下代码解决:

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

注意:请注意,切换可能会错过取消订阅和订阅新可观察对象之间的事件。