I implement an application view model (AVM) object. Anything that needs to get exposed to the application views globally gets implemented as a property in the application view model so that I can get to it via binding. This makes for a nice consistent access method, gets me testability, implements property-change notification, gives me a place to put application-wide commands, all the stuff that you'd expect from using a view model.
The data context for every top-level window is set to the instance of the application view model. So I don't need to mess around with the resource dictionary or remember key values at all. That may sound a little weird at first - why would two windows use the same view model? - but if you want to put the same File/Exit
command on every window that the application spawns, this actually makes logical sense. In such a case, the window's data context is set to the AVM, and then it contains a panel whose data context is set to a property on the AVM that's the actual context for that window. As long as you give your window element a name, binding to objects on the AVM is trivial - {Binding ElementName=TheWindow, Path=DataContext.TheProperty}
- or you could expose the AVM as a property of the child view models.
The AVM pattern is subject to the same pitfalls as any one-object-to-rule-them pattern - e.g. creating a shambling beast with 200 unrelated properties. The solution's the same: aggregate those properties into service classes.
I generally don't put anything in the resource dictionary that doesn't get created in XAML. I can think of lots of valid exceptions to this general rule, but they haven't occurred in my programs yet.