实现可观察的设置类

时间:2016-09-05 09:50:00

标签: c# system.reactive reactive-programming

使用Rx,我有一个设置面板,可以控制是否启用操作以及它们应该以什么速度运行。 这些存储在LibrarySettings类中,当通过前端滑块/复选框对属性进行更改时,observable属性会选择更改。

我应该如何编写LibrarySettings类,使其不将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类中,我需要能够创建属性

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

2 个答案:

答案 0 :(得分:2)

首先,这不是有效的代码(不会编译)

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是不可移植的。
  3. 即。要么只读属性

    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;}
    }
    

    我刚刚找到你链接到的代码(你链接到repo的根目录而不是实际的类) * 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;
        });
    }
    

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

答案 1 :(得分:1)

如果您只是希望超越编译错误,那么您将获胜:

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

或者这个:

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

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