Search code examples
c#reactive-programmingreactive-property

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

  • 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
    

    See: https://okazuki.jp/ReactiveProperty/features/Work-together-with-plane-model-layer-objects.html#two-way-synchronization