Working with Trees in Rx.NET / ReactiveUI

398 views Asked by At

How to observe property changes on any sublevel of a tree?

Consider for example a class TreeNode with the properties Name and ChildNodes. How to observe Name changes on any sublevel of a TreeNode?

The usage might look something like this:

rootNode.FlattenTreeToObservable(x => x.ChildNodes)
        .WhenAnyValue(x => x.Name)
        .Subscribe(...)

TreeNode example:

// NuGet: Install-Package reactiveui
// In case of Splat version issue: Install-Package Splat -Version 1.6.2
using ReactiveUI; 

public class TreeNode: ReactiveObject 
{
    public string Name
    {
        get { return this._name; }
        set { this.RaiseAndSetIfChanged(ref this._name, value); }
    }
    private string _name = "";

    public ReactiveList<TreeNode> ChildNodes
    {
        get { return this._childNodes; }
        set { this.RaiseAndSetIfChanged(ref this._childNodes, value); }
    }
    private ReactiveList<TreeNode> _childNodes = new ReactiveList<TreeNode>();
}
1

There are 1 answers

8
Enigmativity On BEST ANSWER

I couldn't get your code to run - I ended up with a DLL versioning issue so I wrote a basic class that uses the same structure as yours to get this to work:

public class TreeNode
{
    public string Name { get; set; }

    public Subject<TreeNode> ChildNodes { get; }
        = new Subject<TreeNode>();
}

I then added the following method:

    public IObservable<TreeNode> FlattenTreeToObservable()
    {
        return
            this.ChildNodes
                .SelectMany(cn => cn.FlattenTreeToObservable())
                .StartWith(this);
    }

Now when I run this test code:

var root = new TreeNode() { Name = "R" };

root.FlattenTreeToObservable().Subscribe(tn => Console.WriteLine(tn.Name));

var a1 = new TreeNode() { Name = "A1" };
root.ChildNodes.OnNext(a1);

var b11 = new TreeNode() { Name = "B11" };
a1.ChildNodes.OnNext(b11);

var b12 = new TreeNode() { Name = "B12" };
a1.ChildNodes.OnNext(b12);

var a2 = new TreeNode() { Name = "A2" };
root.ChildNodes.OnNext(a2);

var b21 = new TreeNode() { Name = "B21" };
a2.ChildNodes.OnNext(b21);

var b22 = new TreeNode() { Name = "B22" };
a2.ChildNodes.OnNext(b22);  

I get this output:

R
A1
B11
B12
A2
B21
B22