UniRx icon indicating copy to clipboard operation
UniRx copied to clipboard

How to make ReactiveProperty with ReactiveCollection?

Open sericaer opened this issue 5 years ago • 5 comments

for example:

    public ReactiveProperty<int> total { get; private set; }
    public ReactiveCollection<UsedElem> listUsed = new ReactiveCollection<UsedElem>();

    public class UsedElem
    {
        public ReactiveProperty<int> tvalue;
    }

ReactiveProperty total is the sum of tvalue in UsedElem listUsed, listUsed can be insert and remove, and tvalue can also changed.

How to create ReactiveProperty total ?

sericaer avatar Jun 17 '19 07:06 sericaer

tvalue=listUsed.ObserveRemove().ToReactiveProperty(); tvalue=listUsed.ObserveEveryValueChanged(_ => _.Count).ToReactiveProperty();

guopenglun avatar Aug 28 '19 23:08 guopenglun

@guopenglun That won't detect additions, only removals

Zulu-Inuoe avatar Aug 19 '22 13:08 Zulu-Inuoe

I've done this as RxSum You need to observe add, remove, clear, replace and have those subscribeWithStwte using the output total reactive property.

The only issue I have with this is that the output property needs to be disposable and needs to dispose it's 4 subscriptions.

jmprimeau avatar Aug 19 '22 18:08 jmprimeau

I also made the more generic RxAggregate; would be nice to just override the linq methods directly, but I'm afraid of leaking Disposables.

Thoughts on that would be appreciated.

jmprimeau avatar Aug 19 '22 18:08 jmprimeau

Was at the beach when I wrote that... Here's some code. DisposableReadOnlyReactiveProperty is basically a reactive property that carries a disposable that will kill all those subscriptions; Would be happy to see a better alternative.

Also, it seems that SubscribeWithState, passing in aggregated would be better.

public static IDisposableReadOnlyReactiveProperty<TR> RxAggregate<T, TR>( this IReadOnlyReactiveCollection<T> source, TR seed, Func<TR, T, TR> doIt, Func<TR, T, TR> undoIt) { var aggregated = new ReactiveProperty<TR>(source.Aggregate(seed, doIt)); var disposable = new CompositeDisposable(); source.ObserveRemove().Subscribe(args => aggregated.Value = undoIt(aggregated.Value, args.Value)).AddTo(disposable); source.ObserveAdd().Subscribe(args => aggregated.Value = doIt(aggregated.Value, args.Value)).AddTo(disposable); source.ObserveReplace().Subscribe(args => aggregated.Value = doIt(undoIt(aggregated.Value, args.OldValue), args.NewValue)).AddTo(disposable); source.ObserveReset().Subscribe(args => aggregated.Value = seed).AddTo(disposable); return new DisposableReadOnlyReactiveProperty<TR>(aggregated, disposable); }

public static IDisposableReadOnlyReactiveProperty<long> RxSum(this IReadOnlyReactiveCollection<long> source) => source.RxAggregate(0L, (a, b) => a + b, (a, b) => a - b);
public static IDisposableReadOnlyReactiveProperty<int> RxSum(this IReadOnlyReactiveCollection<int> source) => source.RxAggregate(0, (a, b) => a + b, (a, b) => a - b);
public static IDisposableReadOnlyReactiveProperty<float> RxSum(this IReadOnlyReactiveCollection<float> source) => source.RxAggregate(0f, (a, b) => a + b, (a, b) => a - b);
public static IDisposableReadOnlyReactiveProperty<double> RxSum(this IReadOnlyReactiveCollection<double> source) => source.RxAggregate(0d, (a, b) => a + b, (a, b) => a - b);

jmprimeau avatar Aug 23 '22 13:08 jmprimeau