'Better way to attach two ReactiveProperty
Im using ReactiveProperty library in my code and from time to time I need to attach two ReactiveProperty<T> together maintaining property data synchronized. For example by combining a ReactivePropertySlim from a service class to a ReactiveProperty in a ViewModel class.
Usually I use the next code:
// NewProperty is a ViewModel public property
NewProperty = service.Property.ToReactiveProperty<T>();
var propertyDisposable = NewProperty.Subscribe(value => service.Property.Value = value);
Not lookup so bad for a single property but when the number gets high the code gets to.
For now Im using a simple extension method to limit the code repetition.
public static (IReactiveProperty<T> property, IDisposable cleanup) AttachReactiveProperty<T>(this IReactiveProperty<T> baseProperty)
{
var newProperty = baseProperty.ToReactiveProperty<T>();
var cleanup = newProperty.Subscribe(value => baseProperty.Value = value);
return (newProperty, cleanup);
}
I end with a property variable and a IDisposable variable to manage unsubscrition.
var (pausedProperty, pausedDisposable) = remoteConversion.Paused.AttachReactiveProperty();
NewProperty = pausedProperty;
For now the extension is doing his work (less and clear code I think). But is there a better way to approach this problem.
Solution 1:[1]
In this case, you can use ToReactiveProperty[Slim]AsSynchronized extension method that is defined Reactive.Bindings.Extensions namespace.
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
var rp1 = new ReactiveProperty<string>("Init");
ReactiveProperty<string> rp2 = rp1.ToReactivePropertyAsSynchronized(x => x.Value);
ReactivePropertySlim<string> rp3 = rp1.ToReactivePropertySlimAsSynchronized(x => x.Value);
Console.WriteLine("----");
Console.WriteLine(rp1.Value); // Init
Console.WriteLine(rp2.Value); // Init
Console.WriteLine(rp3.Value); // Init
rp1.Value = "Update from rp1";
Console.WriteLine("----");
Console.WriteLine(rp1.Value); // Update from rp1
Console.WriteLine(rp2.Value); // Update from rp1
Console.WriteLine(rp3.Value); // Update from rp1
rp3.Value = "Update from rp3";
Console.WriteLine("----");
Console.WriteLine(rp1.Value); // Update from rp3
Console.WriteLine(rp2.Value); // Update from rp3
Console.WriteLine(rp3.Value); // Update from rp3
// disconnect
rp2.Dispose();
rp3.Dispose();
rp1.Value = "Done";
Console.WriteLine("----");
Console.WriteLine(rp1.Value); // Done
Console.WriteLine(rp2.Value); // Update from rp3
Console.WriteLine(rp3.Value); // Update from rp3
Solution 2:[2]
Well I found a similar but more clean (I think) way to the the same.
In each reactive classes I usually have some CompositeDisposable _cleanup field like this.
public sealed class SomeClass: IDisposable
{
private readonly CompositeDisposable _cleanup = new CompositeDisposable();
public void Dispose()
{
_cleanup.Dispose();
}
}
Then using this basic class contruction and this extension method
internal static class ReactivePropertyEx
{
public static IReactiveProperty<T> AttachReactiveProperty<T>(this IReactiveProperty<T> baseProperty, Action<IDisposable> registerDisposable)
{
var newProperty = baseProperty.ToReactiveProperty<T>();
var cleanup = newProperty.Subscribe(value => baseProperty.Value = value);
registerDisposable(cleanup);
return newProperty;
}
}
The code ends more simple and elegant. The usage is
NewProperty = service.Property.AttachReactiveProperty(disposable => disposable.AddTo(_cleanup));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Kazuki OTA |
| Solution 2 | Alexei Agüero Alba |
