My system is pretty robust, so there were a fair number of up front details to get in place. Basically it creates a root level valuetree in the main app class, which is passed into the business logic classes which either put context specific VT’s (things like the playback transport, a song library, a preset library, a device properties (for our hardware)) and the main component class (which then passes this along to the child components). I also create classes called ValueTreeWrappers which hide the ValueTreeness of this behind a set of setters/getters/callbacks. So, for example, the transport GUI would have a member of TransportProperties (which is a VT wrapper) and it would find this on the main VT passed in with something like transportProperties.wrap (runtimeVT)
. And could then use it’s api for things like transportProperties.onStateChange = [this] (TransportState ts) { updateTransportGuiState (ts); };
or updateTransportGuiState (transportProperties.getState ())'
Once you get used to doing this separation, your coding style adapts to it quickly, and and you can start enjoying the benefits. No more unneeded coupling of GUI components. they truly just become view ports into the underlying data. 