I solved this by adding a Presenter. Essentially, the presenter is a middle-man. All interactions between your UI and the "back end", as you call it, go through the presenter.
Now assuming when you say that "any part of the application can add, remove, and more importantly change the details of those objects at any time", I assume what you mean is that the parts that can initiate some kind of change are always starting from the UI level (unless of course you have some kind of asynchronous task running in the background...)
Since all actions are initiated from the UI, then the presenter knows when anything happens that could change the state. The presenter is responsible for notifying relevant portions of the UI after something happens that could affect its state. The naive, but completely workable solution in many cases, it to always notify all of the displayed parts of the UI after every UI initiated action. (This is workable because in most cases the UI is a flattened representation of a small portion of your "back end", so there usually isn't that much information to synchronize -- the amount of data is limited by your physical screen real-estate.) The notification can be any mechanism (in mine, I just notify the top UI object of the tree, and it passes the message down to all child UI objects). Each UI object is then responsible for looking at the current state, determining if anything changed, and then refreshing what it's displaying if necessary.
Another alternative: a message bus. It's a bit cleaner than events (with events you have to hook up and unhook events to/from objects, and if you forget, you get the equivalent of memory leaks). With a message bus, any object can send a message: "something changed!" and anyone can subscribe to those messages. Check out the messaging infrastructure in MVVM Light for example. It's nice in that it uses soft references, so it doesn't have the potential memory leak issue that events have.