Rx:创建没有主题的可观察对象
Rx: Create observable without subject
对不起,这个标题太简单了,但我不知道还能用什么标题。
我是 Rx 的新手,我正在尝试解决以下情况。
物品来自 collection 供应商的服务器。其中一个供应商将被提名为主要供应商。为了在 WPF 中使它们 editable/bindable 我创建了一些代理反应 objects 将 "react" 更改 UI 并重新计算一些数字。
为了确保只有一个供应商可以成为主要供应商,我实施了以下代码 - 它使用主题来完成工作。
我读过主题 can be a code smell 我想知道我所做的是否 "the right way" 或者是否有更简洁的方法那可以采取。
public class VendorDto
{
public string Name { get; set; }
public bool IsPrimary { get; set; }
}
public class VendorProxy : ReactiveObject
{
// INPC for Name and other properties.
public bool IsPrimary => _isPrimary.Value;
private readonly ObservableAsPropertyHelper<bool> _isPrimary;
public ReactiveCommand<Unit, Unit> MakePrimary { get; }
public VendorProxy(VendorDto dto, IObservable<VendorProxy> primaryVendors, Action<VendorProxy> makePrimary)
{
primaryVendors
.DistinctUntilChanged()
.Select(x => x == this)
.ToProperty(this, x => x.IsPrimary, out _isPrimary);
MakePrimary = ReactiveCommand.Create(() => makePrimary(this),
canExecute: this.WhenAnyValue(x => x.IsPrimary, alreadyPrimary => !alreadyPrimary));
if (dto.IsPrimary)
makePrimary(this); // set the initial value of IsPrimary.
}
// implements IEquality.
}
public class ItemProxy : ReactiveObject
{
private ISubject<VendorProxy> PrimaryVendorSubject { get; } = new BehaviorSubject<VendorProxy>(null);
public IObservable<VendorProxy> PrimaryVendorChanged => PrimaryVendorSubject;
public ReactiveList<VendorProxy> Vendors { get; }
public VendorProxy PrimaryVendor => _primaryVendor.Value;
private readonly ObservableAsPropertyHelper<VendorProxy> _primaryVendor;
public Item()
{
// these come from a web service.
var dtos = new[] {
new Vendor {Name = "Vendor A", IsPrimary = true},
new Vendor {Name = "Vendor B", IsPrimary = false}
}
Vendors = new ReactiveList<VendorProxy>(dtos.Select(dto =>
new VendorProxy(dto, PrimaryVendorChanged, PrimaryVendorSubject.OnNext)));
// some other subscriptions that require the primary vendor to do their work.
}
}
虽然看起来不错,但我无法真正测试它。至于清洁工,那就有点见仁见智了。对我来说,它看起来更具反应性。
我从 ItemProxy
中删除了主题,从 VendorProxy
中删除了 'callback' 操作。 ReactiveCommands
是可观察的,ReactiveList
可以变成可观察的,所以所有这些都可以在 ItemProxy
构造函数中派生(在 primaryStream
变量中)。
public class VendorProxy : ReactiveObject
{
// INPC for Name and other properties.
public bool IsPrimary => _isPrimary.Value;
private readonly ObservableAsPropertyHelper<bool> _isPrimary;
public ReactiveCommand<Unit, Unit> MakePrimary => ReactiveCommand.Create(() => Unit.Default,
canExecute: this.WhenAnyValue(x => x.IsPrimary, alreadyPrimary => !alreadyPrimary));
public VendorProxy(VendorDto dto, IObservable<VendorProxy> primaryVendors)
{
primaryVendors
.DistinctUntilChanged()
.Select(x => x == this)
.ToProperty(this, x => x.IsPrimary, out _isPrimary);
if(dto.IsPrimary)
MakePrimary.Execute();
}
// implements IEquality.
}
public class ItemProxy : ReactiveObject
{
public ReactiveList<VendorProxy> Vendors { get; }
public VendorProxy PrimaryVendor => _primaryVendor.Value;
private readonly ObservableAsPropertyHelper<VendorProxy> _primaryVendor;
public ItemProxy()
{
// these come from a web service.
var dtos = new[] {
new VendorDto {Name = "Vendor A", IsPrimary = true},
new VendorDto {Name = "Vendor B", IsPrimary = false}
};
Vendors = new ReactiveList<VendorProxy>();
var primaryStream = Vendors.ItemsAdded.Select(_ => Unit.Default)
.Merge(Vendors.ItemsRemoved.Select(_ => Unit.Default))
.Select(_ => Observable.Merge(Vendors.Select(v => v.MakePrimary.Select(__ => v))))
.Switch();
primaryStream
.DistinctUntilChanged()
.ToProperty(this, x => x.PrimaryVendor, out _primaryVendor);
var proxies = dtos
.Select(dto => new VendorProxy(dto, primaryStream));
Vendors.AddRange(proxies);
// some other subscriptions that require the primary vendor to do their work.
}
}
对不起,这个标题太简单了,但我不知道还能用什么标题。
我是 Rx 的新手,我正在尝试解决以下情况。
物品来自 collection 供应商的服务器。其中一个供应商将被提名为主要供应商。为了在 WPF 中使它们 editable/bindable 我创建了一些代理反应 objects 将 "react" 更改 UI 并重新计算一些数字。
为了确保只有一个供应商可以成为主要供应商,我实施了以下代码 - 它使用主题来完成工作。
我读过主题 can be a code smell 我想知道我所做的是否 "the right way" 或者是否有更简洁的方法那可以采取。
public class VendorDto
{
public string Name { get; set; }
public bool IsPrimary { get; set; }
}
public class VendorProxy : ReactiveObject
{
// INPC for Name and other properties.
public bool IsPrimary => _isPrimary.Value;
private readonly ObservableAsPropertyHelper<bool> _isPrimary;
public ReactiveCommand<Unit, Unit> MakePrimary { get; }
public VendorProxy(VendorDto dto, IObservable<VendorProxy> primaryVendors, Action<VendorProxy> makePrimary)
{
primaryVendors
.DistinctUntilChanged()
.Select(x => x == this)
.ToProperty(this, x => x.IsPrimary, out _isPrimary);
MakePrimary = ReactiveCommand.Create(() => makePrimary(this),
canExecute: this.WhenAnyValue(x => x.IsPrimary, alreadyPrimary => !alreadyPrimary));
if (dto.IsPrimary)
makePrimary(this); // set the initial value of IsPrimary.
}
// implements IEquality.
}
public class ItemProxy : ReactiveObject
{
private ISubject<VendorProxy> PrimaryVendorSubject { get; } = new BehaviorSubject<VendorProxy>(null);
public IObservable<VendorProxy> PrimaryVendorChanged => PrimaryVendorSubject;
public ReactiveList<VendorProxy> Vendors { get; }
public VendorProxy PrimaryVendor => _primaryVendor.Value;
private readonly ObservableAsPropertyHelper<VendorProxy> _primaryVendor;
public Item()
{
// these come from a web service.
var dtos = new[] {
new Vendor {Name = "Vendor A", IsPrimary = true},
new Vendor {Name = "Vendor B", IsPrimary = false}
}
Vendors = new ReactiveList<VendorProxy>(dtos.Select(dto =>
new VendorProxy(dto, PrimaryVendorChanged, PrimaryVendorSubject.OnNext)));
// some other subscriptions that require the primary vendor to do their work.
}
}
虽然看起来不错,但我无法真正测试它。至于清洁工,那就有点见仁见智了。对我来说,它看起来更具反应性。
我从 ItemProxy
中删除了主题,从 VendorProxy
中删除了 'callback' 操作。 ReactiveCommands
是可观察的,ReactiveList
可以变成可观察的,所以所有这些都可以在 ItemProxy
构造函数中派生(在 primaryStream
变量中)。
public class VendorProxy : ReactiveObject
{
// INPC for Name and other properties.
public bool IsPrimary => _isPrimary.Value;
private readonly ObservableAsPropertyHelper<bool> _isPrimary;
public ReactiveCommand<Unit, Unit> MakePrimary => ReactiveCommand.Create(() => Unit.Default,
canExecute: this.WhenAnyValue(x => x.IsPrimary, alreadyPrimary => !alreadyPrimary));
public VendorProxy(VendorDto dto, IObservable<VendorProxy> primaryVendors)
{
primaryVendors
.DistinctUntilChanged()
.Select(x => x == this)
.ToProperty(this, x => x.IsPrimary, out _isPrimary);
if(dto.IsPrimary)
MakePrimary.Execute();
}
// implements IEquality.
}
public class ItemProxy : ReactiveObject
{
public ReactiveList<VendorProxy> Vendors { get; }
public VendorProxy PrimaryVendor => _primaryVendor.Value;
private readonly ObservableAsPropertyHelper<VendorProxy> _primaryVendor;
public ItemProxy()
{
// these come from a web service.
var dtos = new[] {
new VendorDto {Name = "Vendor A", IsPrimary = true},
new VendorDto {Name = "Vendor B", IsPrimary = false}
};
Vendors = new ReactiveList<VendorProxy>();
var primaryStream = Vendors.ItemsAdded.Select(_ => Unit.Default)
.Merge(Vendors.ItemsRemoved.Select(_ => Unit.Default))
.Select(_ => Observable.Merge(Vendors.Select(v => v.MakePrimary.Select(__ => v))))
.Switch();
primaryStream
.DistinctUntilChanged()
.ToProperty(this, x => x.PrimaryVendor, out _primaryVendor);
var proxies = dtos
.Select(dto => new VendorProxy(dto, primaryStream));
Vendors.AddRange(proxies);
// some other subscriptions that require the primary vendor to do their work.
}
}