CreateDerivedCollection from several collections

128 views
Skip to first unread message

IanYates

unread,
Apr 22, 2013, 11:16:29 PM4/22/13
to reacti...@googlegroups.com
Hi all,
 
This is our first project with ReactiveUI - after a lot of lurking around and watching commits in GitHub and comments on this list we finally get to use ReactiveUI in anger :)
 
We are working on a GUI where we plan to have several "modules" on screen at once - sort of a simple dashboard.  Each module can surface some tabs that I want to display in a ribbon at the top of the screen - this is a ReactiveCollection<RibbonTab> property on the module.  The modules inherit from ReactiveObject. 
 
Additionally, the "host" of the modules can also have its own ribbon tabs.  At the moment I'm looking to have a ViewModel called HostViewModel and a view called HostView.
 
The HostViewModel will have its own private set of tabs which is in a property defined as
ReactiveCollection<RibbonTab> HostTabs  - this is what the host wants to display
 
The HostViewModel also has a collection defined as
ReactiveCollection<ScreenModule> Modules
There's a complimentary property called ActiveModule (of type ScreenModule) to signify which module (if any!) is active.  Any non-active module is still on screen but is smaller.
 
I'd like to combine into a single ReactiveCollection
a) The RibbonTabs exposed by the HostViewModel's HostTabs property
b) The RibbonTabs exposed from the module pointed at by the ActiveModule property.  Noting that there may be no ActiveModule, or that there could be one but its RibbonTabs collection is empty
c) The RibbonTabs exposed by ScreenModules that aren't active
 
They should be in that order.  Extra RibbonTabs could be added by the Host at any time.  The ActiveModule could change to another module (or disappear entirely) - this would involve swapping around tabs (and an activated module may choose to add more tabs too).
 
Is this too complicated for a simple CreateDerivedCollection() call?  I was thinking that if used WhenAny() to listen for changes to the HostTabs.Count property, plus the ActiveModule property, I could create an Observable that would fire whenever the list of tabs needed to be recalculated and pass that to the second overload of CreateDerivedCollection.  However, on what object do I call the CreateDerivedCollection extension method?  It filters and transforms the collection on which it is called - I'm looking for a way to create that initial collection.
 
Would it be best to use my WhenAny() Observable to just loop through and rebuild/reorder a ReactiveCollection<> in a simple loop over the three different RibbonTab collections?  I reckon I can code this without too much fuss (I'd prefer to reorder elements rather than blow away the complete collection and have it rebuilt) but I'm not sure if there's a better way and I'm just missing it.
 
I'm using ReactiveUI v4.6.1 (whatever the just released version is) from NuGet - I'm avoiding the v5 stuff at the moment as per Paul's advice since it's still a bit of a moving target and I couldn't get the NuGet package working properly anyway.
 
Thanks for your help!
 
Cheers,
Ian
 
 

Paul Betts

unread,
Apr 22, 2013, 11:50:29 PM4/22/13
to reacti...@googlegroups.com
Hi Ian,

> Is this too complicated for a simple CreateDerivedCollection() call?

Yep, combining collections is too Fancy™ for CreateDerivedCollection. However,
I assume that these collections won't change too much, right? It's probably
fine to just recompute the list every time.

ObservableAsPropertyHelper<List<RibbonTab>> _AllTheRibbonTabs;
List<RibbonTab> AllTheRibbonTabs {
get { return _AllTheRibbonTabs.Value; }
}

var anyChange = Observable.Merge(
this.WhenAnyObservable(x => x.HostViewModel.HostTabs.CollectionCountChanged),
this.WhenAnyObservable(x => x.ActiveModule.RibbonTabs.CollectionCountChanged),
this.WhenAnyObservable(x => x.ScreenModules.ItemChanged).Select(_ => ScreenModules.Count));

anyChange.Select(_ =>
EnumerableEx.Concat(
HostViewModel.HostTabs,
ActiveModule != null ? ActiveModule.RibbonTabs : Enumerable.Empty<RibbonTabs>(),
ScreenModules.Where(x => !x.Active).SelectMany(x => x.RibbonTabs)))
.ToProperty(this, x => x.AllTheRibbonTabs);

This probably screws up the notifications a bit (i.e. it's not catching every
scenario where you should update the list), but it's a good start

--
Paul Betts <pa...@paulbetts.org>

IanYates

unread,
Apr 23, 2013, 12:55:15 AM4/23/13
to reacti...@googlegroups.com
Hi Paul,
 
Thanks very much for the quick reply.  What you've suggested makes sense to me - I appreciate the code.  I'm glad it's along the lines of how I was thinking I'd implement it :)
 
If the GUI control to which I'm binding this doesn't appreciate the collection being changed (ie, it paints really poorly) then I'll fiddle with the logic to have it rearrange elements rather than recreate the collection from scratch.
 
Cheers,
Ian
Reply all
Reply to author
Forward
0 new messages