0

I have a few objects that contain each a ReactiveList (children), for whose changes I'd like to execute some logic. The parents are dynamic and also in a ReactiveList. Basically I'm doing this:

var parents = new ReactiveList<Parent>();
parents.Add(new Parent() { Id = 1, Children = new ReactiveList<Child>() };
parents.Add(new Parent() { Id = 2, Children = new ReactiveList<Child>() };
parents.Changed
    .SelectMany(_ => parents.Select(x => x.Children.Changed).Merge())
    .Subscribe(x => {
       // Some of the parent's children have changed. But which parent?
    });

// trigger Changed event
parents[1].Children.Add(new Child());

The problem is that I need to know for which of the parents this happened. If I had at least the collection that's being changed, I could retrieve the parent. But I've looked at the NotifyCollectionChangedEventArgs that is passed down and there is nothing useful in there.

So apart from looping "manually" through the parents and subscribing to each, which doesn't look very Rxly to me and probably introduces a bunch of leaking problems, is there an elegant solution?

C. Augusto Proiete
  • 24,684
  • 2
  • 63
  • 91
phreezie
  • 324
  • 2
  • 8

2 Answers2

1

You haven't given us much code to go on, but does this work for you?

var query =
    from parent in parents.Changed
    from child in parent.Children.Changed.Merge()
    select new
    {
        parent,
        child,
    };

query
    .Subscribe((p, c) =>
    {
    });
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • I've updated the example to be bit more verbose. I'm pretty new to the LINQ syntax, so maybe I'm getting something wrong, but your `parent` variable in line 3 is of type `NotifyCollectionChangedEventArgs`, so I can't select `Children` from it. – phreezie Oct 19 '15 at 07:24
  • @phreezie - You didn't provide any class definitions so I didn't know the types involved. Could you please post a complete working example of your code so that I can get the code right? – Enigmativity Oct 19 '15 at 07:52
  • `Parent` would just have `int Id` and `ReactiveList Children`. The `Child` class is irrelevant. Thanks a lot for your input, but I'm going to accept @Gluck's answer below. Cheers! – phreezie Oct 19 '15 at 08:00
  • @phreezie - You do know that Gluck's answer was effectively the same as mine - he just placed the `.Merge()` in a different spot and the variables had slightly different names? – Enigmativity Oct 19 '15 at 08:14
  • I've tried your answer, but maybe the fact that the `.Merge()` was at a different spot made Glucks answer work and yours not? I'm sorry if I wasn't precise enough in my first, unedited post. – phreezie Oct 19 '15 at 08:23
1

Simply save the parent how @Enigmativity suggests :

parents.Changed
    .SelectMany(_ => parents
        .Select(parent => parent.Children.Changed.Select(childEvent =>
            new { parent, childEvent}))
        .Merge())
    .Subscribe(x => {
       // x.parent / x.childEvent
    });

Note that your code will involve a lot of subscriptions (every time the parent list changes, all children subscriptions are re-made), maybe you should consider using the change tracking support from ReactiveList instead ? (if possible, as it won't tell you which child changed)

Gluck
  • 2,933
  • 16
  • 28
  • Thanks, this is what I was looking for! As far as I understood change tracking, it doesn't nest, meaning it would detect if `Children` was re-assigned but not if something *within* `Children` changes (i.e. items added/removed). Am I wrong? – phreezie Oct 19 '15 at 07:58
  • True, you may be able to forward/route children changed events onto your parent, but in the end you're probably good to go with this approach, and if perf comes in as an issue, you can re-write a more optimized version of the stream w/o much changes elsewhere. – Gluck Oct 19 '15 at 08:28
  • Ok, thanks! Now to the real follow-up: With that code, when parents change, the children's subscriptions get properly disposed, right? – phreezie Oct 19 '15 at 08:30