实施可观察设置 class

Implementing an observable settings class

使用 Rx,我有一个设置面板,它控制是否启用操作以及它们应该以什么速率 运行。 这些存储在 LibrarySettings class 中,当通过前端 slider/checkbox 对 属性 进行更改时,observable 属性 会接收到更改。

我应该如何编写 LibrarySettings class,这样它就不会将 setting.Value(整个 LibrarySettings 实例)设置为 null。

IDisposable reader = setting.Value.Subscribe(options =>
{
    OperationOneEnabled = options.OperationOneEnabled;
    OperationTwoEnabled = options.OperationTwoEnabled;

    OperationOneRate = options.OperationOneRate;
    OperationTwoRate = options.OperationTwoRate;     
});

IDisposable writer = this.WhenAnyPropertyChanged()
    .Subscribe(vm =>
    {
        settings.Write(new LibrarySettings(OperationOneEnabled, OperationOneRate,
            OperationTwoEnabled, OperationTwoRate));
    });

OperationOneRateProperty = this.WhenValueChanged(vm => vm.ScheduleRate)
    .DistinctUntilChanged()
    .Select(value => $"{value} seconds")
    .ForBinding();

 _CleanUp = new CompositeDisposable(reader, writer, OperationOneRateProperty);

所以在 LibrarySettings class 我需要能够创建 属性

public IObservable<LibrarySettings> Value
{
    get { return _Value; }
    set { _Value = value; }
}

所以我尝试以下

Value = Observable.Create<LibrarySettings>(() =>
{
    new LibrarySettings(false, OperationOneEnable,OperationOneRate,
        OperationTwoEnabled, OperationTwoRate);
});

并获得

delegate func<IObserver<LibrarySettings>> does not take 0 arguments

如果您只是想绕过编译错误,那么您将获胜:

Value = Observable.Return(new LibrarySettings(/*args*/));

或者这个:

Value = Observable.Create<LibrarySettings>(observer =>
{
    observer.OnNext(new LibrarySettings(/*args*/));
    return Disposable.Empty;
});

听起来你有一个更大的设计问题,但你还没有列出来。

首先,这不是有效代码(无法编译)

Value = Observable.Create<LibrarySettings>(() =>
{
    new LibrarySettings(false, OperationOneEnable,OperationOneRate,
        OperationTwoEnabled, OperationTwoRate);
});

Observable.Create一般以一个Func<IObserver<T>, IDisposable>作为参数,所以应该更正为

Value = Observable.Create<LibrarySettings>(observer =>
{
    observer.OnNext(new LibrarySettings(/*args*/));
    //What to do here?
    return Disposable.Empty; //Yuck.
});

可能更好和更简单的方法是只使用 Observable.Return,但是关于此的观察结果是什么。似乎它使用 Rx 只是为了满足签名,因为这不符合 Rx 的精神。

相反,我想您真正想要的是 Settings 属性,当它发生变化时推送通知。为此我认为有两种合理的做法

  1. 您有一个 LibrarySettings 的只读 属性,其中类型 LibrarySettings 是可变且可观察的。
  2. 您有 LibrarySettings 的可变和可观察 属性,但类型 LibrarySettings 是不可变的。

即只读 属性

this.Setting.WhenAnyPropertyChanged()....

this.Setting.OperationOneRate = 25;
this.Setting.IsOperationOneEnabled= true;

其中类型是可变的

public class LibrarySettings : INotifyPropertyChanged
{
    public LibrarySettings()
    {
        IsOperationOneEnabled = false;;
        OperationOneRate = 0;
        IsOperationTwoEnabled = false;
        OperationTwoRate = 0;
    }
    public bool IsOperationOneEnabled { get;set; }
    public double OperationOneRate { get; set; }
    public bool IsOperationTwoEnabled { get;set; }
    public double OperationTwoRate { get; set;}

    #region INPC Impl
    #region
}

或者不可变类型,然后你改变 属性 (每次都有一个新实例)。您显然希望使用默认值创建它。

this.WhenValueChanges(t=>t.Setting)....

this.Setting = new LibrarySettings(OperationOneEnable, OperationOneRate,
    OperationTwoEnabled, OperationTwoRate);

而且类型...

public class LibrarySettings
{
    public LibrarySettings(bool isOperationOneEnabled, double operationOneRate,
        bool isOperationTwoEnabled, double operationTwoRate)
    {
        IsOperationOneEnabled = isOperationOneEnabled;
        OperationOneRate = operationOneRate;
        IsOperationTwoEnabled = isOperationTwoEnabled;
        OperationTwoRate = operationTwoRate;
    }
    public bool IsOperationOneEnabled { get; }
    public double OperationOneRate { get; }
    public bool IsOperationTwoEnabled { get; }
    public double OperationTwoRate { get;}
}

我刚找到您链接到的代码(您链接到回购协议的根而不是实际的 类 有问题) * https://github.com/markiemarkus/Amadeus/blob/master/Amadeus/NovoApp/Models/LibrarySettings.cs

主要问题是这里的这些行

Value = Observable.Create<LibrarySettings>(observer =>
{
    observer.OnNext(new LibrarySettings(false, OperationOneEnabled, OperationOneRate, OperationTwoEnabled, OperationTwoRate));
    return Disposable.Empty;
});  

}

public IObservable<LibrarySettings> Value
{
     get { return _Value; }
     set { _Value = value; }
}

public void Write(LibrarySettings item)
{
     Value = Observable.Create<LibrarySettings>(observer =>
    {
        observer.OnNext(new LibrarySettings(false, OperationOneEnabled,
        OperationOneRate, OperationTwoEnabled, OperationTwoRate));
        return Disposable.Empty;
    });
}

您创建了一个具有单个值的可观察序列(因此不是真正可观察的)。然后,您通过 属性 和 public setter 公开它(可设置的 IObservable 属性 是什么意思?!)。最后,您在写入方法中覆盖该实例,这意味着实际上订阅了 属性 原始值的任何人都将保留对孤立的 Observable 序列的订阅。