繁体   English   中英

接收:创建无主题的可观察对象

[英]Rx: Create observable without subject

抱歉,标题太简单了,但我不知道该标题还有什么。

我对Rx相当陌生,并尝试解决以下情况。

物品来自服务器并带有一组供应商。 这些供应商之一将被提名为主要供应商。 为了使它们在WPF中可编辑/可绑定,我创建了一些代理反应式对象,这些对象将对UI中的更改进行“反应”并重新计算一些数字。

为了确保只有一个供应商可以成为主要供应商,我实现了以下代码-该代码使用一个主题来完成工作。

我已经读过主题可能是代码的味道,我想知道我所做的是“正确的方法”还是可以采用一种更清洁的方法。

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 ReactiveCommands是可观察的,并且ReactiveList可以变成可观察的,因此所有这些都是可在ItemProxy构造函数中primaryStream (在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. 
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM