【问题标题】:How to change observables at runtime in C#?如何在 C# 中在运行时更改可观察对象?
【发布时间】:2020-08-08 14:30:56
【问题描述】:

考虑让两个 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 作为密钥

【问题讨论】:

    标签: c# system.reactive dynamic-data rx.net


    【解决方案1】:

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

    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
    

    注意:请注意,switch 可能会错过取消订阅和订阅新 observable 之间的事件。

    【讨论】:

    • 谢谢!有用。但是,我不喜欢 ObservableCollection 将两个 SourceCache 混合在一起的事实。查看我的最新编辑,这是基于您的回答。在我的编辑中,我不知道如何处理不同的类型。我会将您的帖子标记为答案。
    • 是的,没错。我一直在寻找更改对象的基类,但没有找到一种方法来组合键控可观察对象而不使用绑定和投影到单元。请注意,这些是合并的可观察对象,但只有一个源可以发出可观察的值。
    • 所以基本上,我需要你的解决方案和我的解决方案的混合体:)
    猜你喜欢
    • 1970-01-01
    • 2016-10-06
    • 2019-12-22
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 2023-01-10
    相关资源
    最近更新 更多