2016-09-05 62 views
1

使用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

+0

你为什么认为setting.Value将变为null? –

+0

@BuhBuh 当LibrarySettings类第一次启动时,它为null。即'新的LibrarySettings(true,20,true,30)'这些已启用并设置了费率属性,但值不是 – Mdev

+0

您是否使用ReactiveUI? – Shlomo

回答

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是免费的。

即无论是只读属性

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

您创建一个具有单一值的可观察序列(这样是不是真的观察到)。然后通过一个公共setter将它暴露出来(可设置的IObservable属性是什么意思?!)。最后,您在写入方法中写入该实例,意味着实际订阅了该属性原始值的任何人都将持有对孤立Observable序列的订阅。

1

如果你只是希望让过去的编译错误,你会用这场比赛的胜利:

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

或本:

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

这听起来像你有一个更大的设计问题你还没有布置。

+0

请查看https://github.com/markiemarkus/Amadeus---Copy 但是,这是一个胜利,以通过编译错误 – Mdev

+0

返回'Disposable.Empty'是如此糟糕的反模式。我强烈建议OP,他们避免这个特殊的'Observable.Create'变种。 – Enigmativity

+0

为什么反模式?这两者在功能上等同。 – Shlomo